<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Présent Composé design</title>
	<atom:link href="https://presentcomposedesign.fr/feed/" rel="self" type="application/rss+xml" />
	<link>https://presentcomposedesign.fr/</link>
	<description>Direction Artistique, concepts &#38; innovations, Design 2D/3D/ia/AR/VR</description>
	<lastBuildDate>Tue, 05 May 2026 08:34:45 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://presentcomposedesign.fr/wp-content/uploads/2025/07/cropped-logo_PCd_2025-512-32x32.png</url>
	<title>Présent Composé design</title>
	<link>https://presentcomposedesign.fr/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Yggdrasil</title>
		<link>https://presentcomposedesign.fr/yggdrasil/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 20 Apr 2026 10:39:50 +0000</pubDate>
				<category><![CDATA[Design produit]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=36494</guid>

					<description><![CDATA[<p>YGGDRASIL — PCdlab 2026 Yggdrasil Plante un arbre. Nourris-le. Sauve la planète. Commencer Nouvelle partie 🌿 Croissance 0% Graine 💧 Eau utilisée 0 L &#160; 🪣 5.2 mL/s Mode Éco Actif : Empreinte Graphique Minimale SOBRIÉTÉ ÉCO (N&#38;B) 5.2 mL/s RICHE COULEUR (DÉTAIL) 87.6 mL/s 🤲 Creuser 🌰 Planter 🫳 Recouvrir 💧 Arroser 📖 Réfléchir i × 🌳 YGGDRASIL — PCdlab 2026 Souris / Clavier 🖱️ Glisser → Orbiter autour de l&#8217;arbre ⚙️ Molette → Zoom avant / arrière Ctrl+Maj+R → Réinitialiser la partie Tactile 👆 1 doigt glissé → Orbiter 🤏 2 doigts pincés → Zoom Quest 3 — Hand Tracking ✊ Pincer (index+pouce) → Arroser 🤚 Mains visibles → Curseur goutte 3D AR → Placer l&#8217;arbre dans l&#8217;espace réel Mode Affichage 🌑 Sobriété N&#038;B = 5.2 mL/s 🌈 Riche Couleur = 87.6 mL/s PCdlab 2026 · PrésentComposédesignCode : Claude Sonnet × Anthropic 📖 La Vérité sur ton Arbre Je comprends 🌱</p>
<p>Cet article <a href="https://presentcomposedesign.fr/yggdrasil/">Yggdrasil</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="36494" class="elementor elementor-36494">
				<div class="elementor-element elementor-element-6fddc91 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="6fddc91" data-element_type="container" data-e-type="container">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-f2f4319 elementor-widget elementor-widget-html" data-id="f2f4319" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!--
╔══════════════════════════════════════════════════════════════════════════════════════════╗
║  YGGDRASIL — Plante ton arbre, sauve la planète                                          ║
║  PCdlab 2026 · PrésentComposédesign × Claude Sonnet (Anthropic)                          ║
╚══════════════════════════════════════════════════════════════════════════════════════════╝

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+#@@@@@@%. :%@@@@@@*+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.  .#@@@*     *@@@*.  =@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@@@@@@@@:    #@*       *@#    +@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.  -#%@@@@@@-   #%=       +%#   -@@@@@@%*:  .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.     .@@@@@@%*+%%    @   :%%++%@@@@@@.     .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@*    #@@.      .%@%   =%@@*   @   *@@%-   @@#.      .@@#    *@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@=    -@#   ::  -@%     -@%:  @  :%@-     %@-  =.   %@-    *@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@%%   *@%    # -@%       @%-:@:-%@       %%: %   :%@+   %%@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@**=+**#@@@@@@+::%#@@   :.  :@@@@@@@:  ..   @@@@.:+@@@@@@#***+*#@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@=       :#@@@%*%%@@@@.  += :@@@@@@@: -=  .@@@@@%+@@@@#:       %@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@:     .%%          @@-     *@@*     =@@         *@%      -@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@=      *%-    :=: .@+        #@@@@@%:   :%@@@@@#       .*%. :=:    +@- .    =@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@+.  :*@@#+    :@*%@:        +@@@#.     .#@@@+        :@#*@:    *#@@@:   +%@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@%%%%%%@@@@@@@@@@@@@@@@    :=  -%@%        :%@#:  =.    @@@@@%%@@@@@@@@@%%%%%%@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  ╭─────────────────────────────────────────────────────────────╮
  │  ░░░ CLAUDE SONNET — Anthropic AI ░░░                       │
  │  Code : PCdlab 2026 — WebXR / Three.js / Quest 3            │
  │  Fix : display !important override · Hand Tracking           │
  ╰─────────────────────────────────────────────────────────────╯
-->
<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="theme-color" content="#0a1008">
  <title>YGGDRASIL — PCdlab 2026</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
  <style>
    /* ═══════════════════════════════════════════════════════════════
       YGGDRASIL — CSS ISOLATION WORDPRESS / ELEMENTOR / ROYAL ADDONS
       ─ Tous les sélecteurs scoped sous #ygg-pcdb-root
       ─ !important uniquement sur les props de LAYOUT (jamais sur display
         des éléments contrôlés par JS → sinon le JS ne peut plus les cacher)
       ═══════════════════════════════════════════════════════════════ */

    html, body { margin: 0 !important; padding: 0 !important; overflow: hidden !important; }

    /* ─── ROOT ─── */
    #ygg-pcdb-root {
      position: fixed !important;
      inset: 0 !important;
      width: 100% !important; height: 100% !important;
      overflow: hidden !important;
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
      font-size: 14px !important; line-height: 1.5 !important;
      background: #0a1008 !important;
      z-index: 99998 !important;
      box-sizing: border-box !important;
    }
    #ygg-pcdb-root *, #ygg-pcdb-root *::before, #ygg-pcdb-root *::after {
      box-sizing: border-box !important;
      margin: 0 !important; padding: 0 !important;
      /* PAS de border:none ici — on le met par sélecteur précis */
      font-family: inherit !important;
      -webkit-tap-highlight-color: transparent !important;
    }

    /* ─── CANVAS ─── */
    #ygg-pcdb-root #ygg-canvas {
      position: absolute !important;
      inset: 0 !important; display: block !important;
      width: 100% !important; height: 100% !important;
      z-index: 1 !important;
      transition: filter 0.9s ease !important;
    }
    #ygg-pcdb-root #ygg-canvas.ygg-nb {
      filter: grayscale(1) contrast(1.06) brightness(0.95) !important;
    }

    /* ─── UI LAYER ─── */
    #ygg-pcdb-root #ygg-ui {
      position: absolute !important; inset: 0 !important;
      z-index: 10 !important; pointer-events: none !important;
    }
    #ygg-pcdb-root #ygg-ui > * { pointer-events: auto !important; }

    /* ─── CARD ─── */
    #ygg-pcdb-root .ygg-card {
      background: rgba(8,14,8,0.85) !important;
      backdrop-filter: blur(14px) !important; -webkit-backdrop-filter: blur(14px) !important;
      border: 1px solid rgba(100,160,80,0.28) !important;
      border-radius: 10px !important; padding: 10px 14px !important;
      color: #c8dfc0 !important; font-size: 12px !important;
      pointer-events: auto !important;
    }
    #ygg-pcdb-root .ygg-lbl {
      font-size: 9px !important; text-transform: uppercase !important;
      letter-spacing: 1.3px !important; color: rgba(130,185,110,0.55) !important;
      margin-bottom: 3px !important; display: block !important;
    }
    #ygg-pcdb-root .ygg-val {
      font-size: 18px !important; font-weight: 600 !important;
      color: #9de090 !important; font-family: 'Playfair Display', Georgia, serif !important;
      display: block !important;
    }
    #ygg-pcdb-root .ygg-val.blue { color: #7ec8e3 !important; }
    #ygg-pcdb-root .ygg-sub {
      font-size: 10px !important; color: rgba(150,195,130,0.45) !important;
      margin-top: 2px !important; display: block !important;
    }

    /* ─── HUD ─── */
    #ygg-pcdb-root #ygg-hud {
      position: absolute !important;
      top: 12px !important; left: 12px !important; right: 12px !important;
      display: none; /* contrôlé par JS — PAS de !important */
      justify-content: space-between !important; align-items: flex-start !important;
      z-index: 20 !important; pointer-events: none !important;
    }
    #ygg-pcdb-root #ygg-hud > * { pointer-events: auto !important; }
    #ygg-pcdb-root #ygg-growth-card { max-width: 195px !important; }
    #ygg-pcdb-root #ygg-water-card  { max-width: 195px !important; text-align: right !important; }

    /* ─── LOGO CENTRE ─── */
    #ygg-pcdb-root #ygg-logo-center { text-align: center !important; pointer-events: none !important; }
    #ygg-pcdb-root #ygg-logo-img {
      width: 68px !important; height: 68px !important; object-fit: contain !important;
      transition: filter 0.8s ease !important;
      filter: drop-shadow(0 0 8px rgba(80,180,80,0.35)) !important;
    }
    /* Logo N&B : inversion pour fond sombre */
    #ygg-pcdb-root #ygg-logo-img.ygg-nb-logo {
      filter: brightness(0) invert(1) opacity(0.85) !important;
    }
    #ygg-pcdb-root #ygg-intro-logo {
      width: 110px !important; height: 110px !important; object-fit: contain !important;
      margin-bottom: 22px !important;
      animation: ygg-float 3.2s ease-in-out infinite !important;
      /* Logo intro en N&B : inversion pour fond sombre */
      filter: brightness(0) invert(1) opacity(0.9) !important;
    }
    #ygg-pcdb-root #ygg-intro-logo.ygg-color-logo {
      filter: drop-shadow(0 0 18px rgba(80,200,80,0.35)) !important;
    }

    /* ─── TOGGLE BAR ─── */
    #ygg-pcdb-root #ygg-toggle-bar {
      position: absolute !important;
      bottom: 80px !important; left: 50% !important;
      transform: translateX(-50%) !important;
      display: none; /* contrôlé par JS */
      align-items: center !important; gap: 14px !important;
      background: rgba(6,10,6,0.9) !important;
      backdrop-filter: blur(14px) !important; -webkit-backdrop-filter: blur(14px) !important;
      border: 1px solid rgba(100,160,80,0.22) !important;
      border-radius: 14px !important; padding: 10px 18px !important;
      z-index: 20 !important; white-space: nowrap !important;
    }
    #ygg-pcdb-root .ygg-tside {
      display: flex !important; flex-direction: column !important;
      align-items: center !important; gap: 3px !important;
    }
    #ygg-pcdb-root .ygg-tlabel {
      font-size: 9px !important; text-transform: uppercase !important;
      letter-spacing: 1px !important; color: rgba(130,185,110,0.5) !important;
    }
    #ygg-pcdb-root .ygg-cdisp {
      font-size: 13px !important; font-weight: 700 !important;
      font-family: 'Playfair Display', Georgia, serif !important;
    }
    #ygg-pcdb-root .ygg-cdisp.eco { color: #7ec8a0 !important; }
    #ygg-pcdb-root .ygg-cdisp.rich { color: #e07c4a !important; }
    #ygg-pcdb-root .ygg-cunit {
      font-size: 9px !important; font-weight: 400 !important;
      font-family: 'Inter', sans-serif !important; opacity: 0.7 !important;
    }
    /* Toggle switch */
    #ygg-pcdb-root #ygg-toggle-btn {
      position: relative !important;
      width: 52px !important; height: 28px !important;
      background: rgba(30,50,30,0.8) !important;
      border: 1.5px solid rgba(100,160,80,0.5) !important;
      border-radius: 14px !important; cursor: pointer !important;
      flex-shrink: 0 !important; transition: background 0.4s !important;
    }
    #ygg-pcdb-root #ygg-toggle-btn.ygg-on {
      background: rgba(100,45,10,0.8) !important;
      border-color: rgba(200,120,60,0.5) !important;
    }
    #ygg-pcdb-root #ygg-toggle-thumb {
      position: absolute !important;
      width: 22px !important; height: 22px !important;
      top: 2px !important; left: 2px !important;
      background: rgba(100,200,100,0.9) !important;
      border-radius: 50% !important;
      transition: left 0.3s ease, background 0.4s !important;
      display: flex !important; align-items: center !important; justify-content: center !important;
      overflow: hidden !important;
    }
    #ygg-pcdb-root #ygg-toggle-btn.ygg-on #ygg-toggle-thumb {
      left: 26px !important; background: rgba(210,120,50,0.9) !important;
    }
    #ygg-pcdb-root #ygg-toggle-logo {
      width: 18px !important; height: 18px !important; object-fit: contain !important;
    }

    /* ─── CONSOMMATION ACTIVE ─── */
    #ygg-pcdb-root #ygg-active-cons {
      position: absolute !important;
      top: 12px !important; left: 50% !important; transform: translateX(-50%) !important;
      background: rgba(6,10,6,0.87) !important;
      backdrop-filter: blur(12px) !important; -webkit-backdrop-filter: blur(12px) !important;
      border: 1px solid rgba(100,160,80,0.2) !important;
      border-radius: 8px !important; padding: 6px 14px !important;
      display: none; /* contrôlé par JS */
      align-items: center !important; gap: 10px !important;
      font-size: 11px !important; color: #c8dfc0 !important;
      z-index: 20 !important; white-space: nowrap !important;
    }
    #ygg-pcdb-root #ygg-cons-icon { font-size: 16px !important; }
    #ygg-pcdb-root #ygg-cons-val {
      font-size: 16px !important; font-weight: 700 !important;
      font-family: 'Playfair Display', Georgia, serif !important;
      color: #9de090 !important; transition: color 0.5s !important;
    }
    #ygg-pcdb-root #ygg-cons-val.rich { color: #e07c4a !important; }
    #ygg-pcdb-root #ygg-cons-desc {
      font-size: 9px !important; color: rgba(150,195,130,0.5) !important;
    }

    /* ─── BOUTONS ACTION
         NOTE CRITIQUE : PAS de display !important ici.
         La visibilité est gérée par JS (inline style).
         Si on met display:flex !important, le JS ne peut plus cacher les boutons. ─── */
    #ygg-pcdb-root #ygg-actions {
      position: absolute !important;
      bottom: 20px !important; left: 50% !important; transform: translateX(-50%) !important;
      display: none; /* contrôlé par JS */
      gap: 8px !important; z-index: 20 !important;
      flex-wrap: wrap !important; justify-content: center !important;
      max-width: 90vw !important;
    }
    #ygg-pcdb-root .ygg-btn {
      background: rgba(8,14,8,0.84);
      backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
      border: 1px solid rgba(100,160,80,0.35);
      border-radius: 10px; padding: 11px 20px;
      color: #c8dfc0; font-family: 'Inter', sans-serif !important;
      font-size: 13px; font-weight: 500; cursor: pointer;
      /* display: flex sans !important → le JS peut le contrôler */
      display: flex; align-items: center; gap: 7px;
      white-space: nowrap;
      transition: background 0.22s, border-color 0.22s, transform 0.1s;
    }
    #ygg-pcdb-root .ygg-btn:hover {
      background: rgba(30,60,30,0.78);
      border-color: rgba(100,190,80,0.52);
    }
    #ygg-pcdb-root .ygg-btn:active { transform: scale(0.96); }

    /* ─── BOUTONS XR ─── */
    #ygg-pcdb-root #ygg-xr-btns {
      position: absolute !important; bottom: 20px !important; right: 12px !important;
      display: flex !important; gap: 8px !important; z-index: 20 !important;
    }
    #ygg-pcdb-root .ygg-xrbtn {
      background: rgba(8,16,26,0.84);
      backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
      border: 1px solid rgba(80,140,200,0.4);
      border-radius: 10px; padding: 11px 18px;
      color: #a0c8e8; font-family: 'Inter', sans-serif !important;
      font-size: 13px; font-weight: 500; cursor: pointer;
      transition: background 0.22s;
    }
    #ygg-pcdb-root .ygg-xrbtn:hover { background: rgba(20,40,80,0.78); }

    /* ─── MESSAGE ÉCO ─── */
    #ygg-pcdb-root #ygg-eco-msg {
      position: absolute !important;
      bottom: 140px !important; left: 50% !important; transform: translateX(-50%) !important;
      background: rgba(4,8,4,0.92) !important;
      backdrop-filter: blur(14px) !important; -webkit-backdrop-filter: blur(14px) !important;
      border: 1px solid rgba(100,160,80,0.2) !important;
      border-radius: 10px !important; padding: 14px 20px !important;
      max-width: 460px !important; width: calc(100vw - 24px) !important;
      text-align: center !important; color: #c8dfc0 !important;
      font-size: 12px !important; line-height: 1.65 !important;
      z-index: 20 !important;
      opacity: 0; pointer-events: none !important;
      transition: opacity 0.7s ease !important;
    }
    #ygg-pcdb-root #ygg-eco-msg.vis { opacity: 1 !important; }
    #ygg-pcdb-root .ygg-etitle {
      font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 14px !important; color: #9de090 !important;
      margin-bottom: 6px !important; display: block !important;
    }

    /* ─── JOURNAL ─── */
    #ygg-pcdb-root #ygg-journal {
      position: absolute !important;
      top: 100px !important; right: 12px !important;
      background: rgba(8,14,8,0.8) !important;
      backdrop-filter: blur(12px) !important; -webkit-backdrop-filter: blur(12px) !important;
      border: 1px solid rgba(100,160,80,0.18) !important;
      border-radius: 10px !important; padding: 10px !important;
      width: 210px !important; max-height: 275px !important; overflow-y: auto !important;
      display: none; z-index: 20 !important;
    }
    #ygg-pcdb-root #ygg-journal::-webkit-scrollbar { width: 4px !important; }
    #ygg-pcdb-root #ygg-journal::-webkit-scrollbar-thumb {
      background: rgba(100,160,80,0.3) !important; border-radius: 2px !important;
    }
    #ygg-pcdb-root .ygg-entry {
      font-size: 10px !important; color: rgba(165,205,150,0.65) !important;
      padding: 3px 0 !important; border-bottom: 1px solid rgba(100,160,80,0.1) !important;
      line-height: 1.44 !important;
    }
    #ygg-pcdb-root .ygg-entry:last-child { border-bottom: none !important; }
    #ygg-pcdb-root .ygg-etime { color: rgba(100,160,80,0.45) !important; }

    /* ─── BOUTON INFO ─── */
    #ygg-pcdb-root #ygg-info-btn {
      position: absolute !important; bottom: 20px !important; left: 12px !important;
      width: 42px !important; height: 42px !important;
      background: rgba(8,14,8,0.84) !important;
      backdrop-filter: blur(12px) !important; -webkit-backdrop-filter: blur(12px) !important;
      border: 1px solid rgba(100,160,80,0.35) !important; border-radius: 50% !important;
      color: #9de090 !important; font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 18px !important; font-style: italic !important; font-weight: 700 !important;
      cursor: pointer !important; z-index: 21 !important;
      display: flex !important; align-items: center !important; justify-content: center !important;
      transition: background 0.22s !important;
    }
    #ygg-pcdb-root #ygg-info-btn:hover { background: rgba(25,55,25,0.88) !important; }

    /* ─── PANNEAU AIDE ─── */
    #ygg-pcdb-root #ygg-help-panel {
      position: absolute !important; bottom: 72px !important; left: 12px !important;
      width: 295px !important; max-width: calc(100vw - 24px) !important;
      background: rgba(4,8,4,0.96) !important;
      backdrop-filter: blur(18px) !important; -webkit-backdrop-filter: blur(18px) !important;
      border: 1px solid rgba(100,160,80,0.26) !important;
      border-radius: 12px !important; padding: 16px !important;
      z-index: 22 !important; color: #c8dfc0 !important;
    }
    #ygg-pcdb-root #ygg-help-panel[hidden] { display: none !important; }
    #ygg-pcdb-root #ygg-help-close {
      position: absolute !important; top: 10px !important; right: 12px !important;
      background: none !important; border: none !important;
      color: rgba(150,195,130,0.5) !important;
      font-size: 20px !important; cursor: pointer !important; padding: 2px 6px !important;
    }
    #ygg-pcdb-root #ygg-help-close:hover { color: #9de090 !important; }
    #ygg-pcdb-root #ygg-help-panel h2 {
      font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 15px !important; color: #9de090 !important; margin-bottom: 10px !important;
    }
    #ygg-pcdb-root #ygg-help-panel h3 {
      font-size: 9px !important; text-transform: uppercase !important;
      letter-spacing: 1.2px !important; color: rgba(130,185,110,0.5) !important;
      margin: 8px 0 5px !important;
    }
    #ygg-pcdb-root #ygg-help-panel ul { list-style: none !important; }
    #ygg-pcdb-root #ygg-help-panel li {
      font-size: 11px !important; color: rgba(185,215,170,0.75) !important;
      padding: 2px 0 !important; line-height: 1.5 !important;
    }
    #ygg-pcdb-root .ygg-credit {
      margin-top: 10px !important; font-size: 9px !important;
      color: rgba(110,155,90,0.4) !important; text-align: center !important;
      padding-top: 8px !important; border-top: 1px solid rgba(100,160,80,0.1) !important;
    }

    /* ─── FLASH PINCH XR ─── */
    #ygg-pcdb-root #ygg-pinch-flash {
      position: absolute !important; inset: 0 !important;
      background: rgba(80,200,255,0.07) !important;
      z-index: 18 !important; pointer-events: none !important;
      opacity: 0 !important; transition: opacity 0.12s !important;
    }
    #ygg-pcdb-root #ygg-pinch-flash.fl { opacity: 1 !important; }

    /* ─── INTRO ─── */
    #ygg-pcdb-root #ygg-intro {
      position: absolute !important; inset: 0 !important;
      background: radial-gradient(ellipse at 50% 75%, #182a1a 0%, #050c05 70%) !important;
      z-index: 50 !important;
      display: flex !important; flex-direction: column !important;
      align-items: center !important; justify-content: center !important;
      text-align: center !important; padding: 30px !important;
      transition: opacity 1.1s ease !important;
    }
    #ygg-pcdb-root #ygg-intro.ygg-out {
      opacity: 0 !important; pointer-events: none !important;
    }
    #ygg-pcdb-root #ygg-intro h1 {
      font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 46px !important; color: #9de090 !important;
      letter-spacing: 3px !important; margin-bottom: 6px !important;
    }
    #ygg-pcdb-root .ygg-sub-intro {
      font-size: 13px !important; font-style: italic !important;
      color: rgba(165,205,150,0.5) !important; margin-bottom: 34px !important;
    }
    #ygg-pcdb-root #ygg-start-btn {
      background: rgba(35,72,35,0.45) !important;
      border: 1px solid rgba(100,190,80,0.45) !important;
      border-radius: 12px !important; padding: 16px 44px !important;
      color: #9de090 !important; font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 18px !important; cursor: pointer !important;
      transition: background 0.28s !important; margin-bottom: 14px !important;
    }
    #ygg-pcdb-root #ygg-start-btn:hover { background: rgba(45,90,45,0.58) !important; }
    #ygg-pcdb-root #ygg-reset-btn {
      font-size: 10px !important; color: rgba(110,155,90,0.36) !important;
      cursor: pointer !important; background: none !important; border: none !important;
      text-decoration: underline !important; text-underline-offset: 3px !important;
    }

    /* ─── MORAL ─── */
    #ygg-pcdb-root #ygg-moral {
      position: absolute !important; inset: 0 !important;
      background: rgba(2,4,2,0.96) !important;
      z-index: 60 !important;
      display: flex !important; flex-direction: column !important;
      align-items: center !important; justify-content: center !important;
      padding: 30px !important; text-align: center !important; overflow-y: auto !important;
    }
    #ygg-pcdb-root #ygg-moral[hidden] { display: none !important; }
    #ygg-pcdb-root #ygg-moral h2 {
      font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 25px !important; color: #e6a8a8 !important; margin-bottom: 16px !important;
    }
    #ygg-pcdb-root #ygg-moral-text {
      font-size: 13px !important; color: rgba(215,195,185,0.75) !important;
      max-width: 500px !important; line-height: 1.8 !important; margin-bottom: 12px !important;
    }
    #ygg-pcdb-root .ygg-mstat {
      font-size: 17px !important; color: #7ec8e3 !important;
      font-weight: 600 !important; margin: 12px 0 !important; line-height: 1.7 !important;
    }
    #ygg-pcdb-root #ygg-moral-advice {
      font-size: 13px !important; color: rgba(215,195,185,0.65) !important;
      max-width: 500px !important; line-height: 1.8 !important; margin-bottom: 20px !important;
    }

    /* ─── ANIMATIONS ─── */
    @keyframes ygg-float {
      0%, 100% { transform: translateY(0); }
      50% { transform: translateY(-9px); }
    }
  </style>
</head>
<body>
<div id="ygg-pcdb-root">

  <canvas id="ygg-canvas"></canvas>

  <div id="ygg-ui">

    <!-- INTRO -->
    <div id="ygg-intro">
      <img decoding="async" id="ygg-intro-logo" src="https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1stroke_PCdlab_2026.svg" alt="Yggdrasil">
      <h1>Yggdrasil</h1>
      <p class="ygg-sub-intro">Plante un arbre. Nourris-le. Sauve la planète.</p>
      <button id="ygg-start-btn" type="button">Commencer</button>
      <button id="ygg-reset-btn" type="button">Nouvelle partie</button>
    </div>

    <!-- HUD -->
    <div id="ygg-hud">
      <div class="ygg-card" id="ygg-growth-card">
        <span class="ygg-lbl">🌿 Croissance</span>
        <span class="ygg-val" id="ygg-growth-val">0%</span>
        <span class="ygg-sub" id="ygg-stage-name">Graine</span>
      </div>
      <div id="ygg-logo-center">
        <img decoding="async" id="ygg-logo-img"
          src="https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1stroke_PCdlab_2026.svg"
          alt="YGGDRASIL" class="ygg-nb-logo">
      </div>
      <div class="ygg-card" id="ygg-water-card">
        <span class="ygg-lbl">💧 Eau utilisée</span>
        <span class="ygg-val blue" id="ygg-water-val">0 L</span>
        <span class="ygg-sub" id="ygg-water-eq">&nbsp;</span>
      </div>
    </div>

    <!-- CONSOMMATION ACTIVE -->
    <div id="ygg-active-cons">
      <span id="ygg-cons-icon">🪣</span>
      <span id="ygg-cons-val">5.2 mL/s</span>
      <span id="ygg-cons-desc">Mode Éco Actif : Empreinte Graphique Minimale</span>
    </div>

    <!-- TOGGLE -->
    <div id="ygg-toggle-bar">
      <div class="ygg-tside">
        <span class="ygg-tlabel">SOBRIÉTÉ ÉCO (N&amp;B)</span>
        <span class="ygg-cdisp eco"><span id="ygg-eco-v">5.2</span><span class="ygg-cunit"> mL/s</span></span>
      </div>
      <button id="ygg-toggle-btn" type="button" role="switch" aria-checked="false" aria-label="Mode affichage">
        <span id="ygg-toggle-thumb">
          <img decoding="async" id="ygg-toggle-logo"
            src="https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1_PCdlab_2026.svg"
            alt="" aria-hidden="true">
        </span>
      </button>
      <div class="ygg-tside">
        <span class="ygg-tlabel">RICHE COULEUR (DÉTAIL)</span>
        <span class="ygg-cdisp rich"><span id="ygg-rich-v">87.6</span><span class="ygg-cunit"> mL/s</span></span>
      </div>
    </div>

    <!-- JOURNAL -->
    <div id="ygg-journal" aria-live="polite"></div>

    <!-- ACTIONS — boutons cachés/montrés individuellement par JS -->
    <div id="ygg-actions">
      <button class="ygg-btn" id="ygg-btn-dig"   type="button">🤲 Creuser</button>
      <button class="ygg-btn" id="ygg-btn-plant" type="button" style="display:none">🌰 Planter</button>
      <button class="ygg-btn" id="ygg-btn-cover" type="button" style="display:none">🫳 Recouvrir</button>
      <button class="ygg-btn" id="ygg-btn-water" type="button" style="display:none">💧 Arroser</button>
      <button class="ygg-btn" id="ygg-btn-moral" type="button" style="display:none">📖 Réfléchir</button>
    </div>

    <!-- XR (injectés si disponibles) -->
    <div id="ygg-xr-btns"></div>

    <!-- ECO MSG -->
    <div id="ygg-eco-msg" role="status" aria-live="polite"></div>

    <!-- FLASH XR -->
    <div id="ygg-pinch-flash"></div>

    <!-- BOUTON INFO -->
    <button id="ygg-info-btn" type="button" aria-label="Aide et commandes" aria-expanded="false">i</button>

    <!-- PANNEAU AIDE -->
    <div id="ygg-help-panel" role="dialog" aria-label="Aide" hidden>
      <button id="ygg-help-close" type="button" aria-label="Fermer">×</button>
      <h2>🌳 YGGDRASIL — PCdlab 2026</h2>
      <h3>Souris / Clavier</h3>
      <ul>
        <li>🖱️ Glisser → Orbiter autour de l'arbre</li>
        <li>⚙️ Molette → Zoom avant / arrière</li>
        <li>Ctrl+Maj+R → Réinitialiser la partie</li>
      </ul>
      <h3>Tactile</h3>
      <ul>
        <li>👆 1 doigt glissé → Orbiter</li>
        <li>🤏 2 doigts pincés → Zoom</li>
      </ul>
      <h3>Quest 3 — Hand Tracking</h3>
      <ul>
        <li>✊ Pincer (index+pouce) → Arroser</li>
        <li>🤚 Mains visibles → Curseur goutte 3D</li>
        <li>AR → Placer l'arbre dans l'espace réel</li>
      </ul>
      <h3>Mode Affichage</h3>
      <ul>
        <li>🌑 Sobriété N&B = <strong>5.2 mL/s</strong></li>
        <li>🌈 Riche Couleur = <strong>87.6 mL/s</strong></li>
      </ul>
      <p class="ygg-credit">PCdlab 2026 · PrésentComposédesign<br>Code : Claude Sonnet × Anthropic</p>
    </div>

    <!-- MORAL -->
    <div id="ygg-moral" role="dialog" aria-modal="true" hidden>
      <h2>📖 La Vérité sur ton Arbre</h2>
      <p id="ygg-moral-text"></p>
      <div class="ygg-mstat" id="ygg-moral-stat"></div>
      <p id="ygg-moral-advice"></p>
      <button class="ygg-btn" id="ygg-close-moral" type="button">Je comprends 🌱</button>
    </div>

  </div><!-- #ygg-ui -->
</div><!-- #ygg-pcdb-root -->

<script type="module">
/* ══════════════════════════════════════════════════════════════════════
   YGGDRASIL — PCdlab 2026
   Three.js 0.161 · WebXR · Hand Tracking Quest 3
   Bug Fix : display !important removed from .ygg-btn
             → JS peut maintenant gérer la visibilité des boutons
   ══════════════════════════════════════════════════════════════════════ */

import * as THREE from 'https://unpkg.com/three@0.161.0/build/three.module.js';

/* ─── CONSTANTES ─── */
const SAVE_KEY    = 'ygg_pcdb_2026';
const WATER_PAGE  = 0.5;
const WATER_ARR   = 1.5;
const SHOWER_LPM  = 12;
const CONS_ECO    = 5.2;
const CONS_RICH   = 87.6;

const LOGO_GRADIENT = 'https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_gradient_PCdlab_2026.svg';
const LOGO_STROKE   = 'https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1stroke_PCdlab_2026.svg';
const LOGO_MAIN     = 'https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1_PCdlab_2026.svg';

const GOLDEN_ANGLE = Math.PI * 2 * (1 - 2 / (1 + Math.sqrt(5)));
const FIB = [2, 3, 5, 8, 13, 21, 34];

const STAGES = [
  { name:'Graine',       min:0  },
  { name:'Germination',  min:5  },
  { name:'Jeune pousse', min:15 },
  { name:'Arbuste',      min:30 },
  { name:'Jeune arbre',  min:50 },
  { name:'Arbre mature', min:70 },
  { name:'Yggdrasil',   min:90 },
];

const ECO_FACTS = [
  "🚿 Une douche de 5 min = 60 litres.",
  "🥩 1 kg de bœuf = 15 400 litres d'eau.",
  "👕 Un t-shirt coton = 2 700 litres.",
  "🌾 L'agriculture utilise 70% de l'eau douce mondiale.",
  "💧 2,2 milliards sans accès à l'eau potable.",
  "🌍 La moitié du monde en stress hydrique d'ici 2025.",
  "☕ Une tasse de café = 140 litres produits.",
  "📱 Un smartphone = 12 000 litres fabriqué.",
  "🥑 Un avocat = 320 litres d'eau.",
  "🏠 Un Français consomme ~150 L/jour.",
];

/* ─── ÉTAT ─── */
function defaultState() {
  return {
    phase:'start', growth:0, totalWater:0,
    waterCount:0, pageLoads:0, pageWater:0,
    lastWaterTime:null, createdAt:Date.now(),
    journal:[], overwatered:false,
  };
}
function loadState() {
  try { const d = JSON.parse(localStorage.getItem(SAVE_KEY)); if (d?.phase) return d; } catch(e){}
  return defaultState();
}
let gs = loadState();
const save = () => localStorage.setItem(SAVE_KEY, JSON.stringify(gs));

gs.pageLoads = (gs.pageLoads||0) + 1;
gs.pageWater = (gs.pageWater||0) + WATER_PAGE;
save();

/* ─── TOGGLE STATE ─── */
let isColor = false;

/* ─── THREE.JS ─── */
const canvas = document.getElementById('ygg-canvas');

const renderer = new THREE.WebGLRenderer({ canvas, antialias:true, alpha:false });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.95;
renderer.xr.enabled = true;

const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x162617, 0.013);

const camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 0.1, 200);

/* worldGroup : tout l'environnement. Déplacé en XR pour positionner l'utilisateur */
const worldGroup = new THREE.Group();
scene.add(worldGroup);

/* ─── LUMIÈRES ─── */
scene.add(new THREE.AmbientLight(0x3a5a3a, 0.72));

const sun = new THREE.DirectionalLight(0xffe8c0, 1.28);
sun.position.set(8, 15, 5);
sun.castShadow = true;
sun.shadow.mapSize.set(2048, 2048);
sun.shadow.camera.near = 0.5; sun.shadow.camera.far = 60;
sun.shadow.camera.left = -18; sun.shadow.camera.right = 18;
sun.shadow.camera.top  = 18; sun.shadow.camera.bottom = -18;
sun.shadow.bias = -0.001; sun.shadow.normalBias = 0.02;
scene.add(sun);

const rim = new THREE.DirectionalLight(0x88aaff, 0.32);
rim.position.set(-5, 8, -5);
scene.add(rim);

/* ─── CIEL (dégradé shader) ─── */
const skyMat = new THREE.ShaderMaterial({
  side: THREE.BackSide,
  uniforms: {
    topColor:    { value: new THREE.Color(0x0a1628) },
    bottomColor: { value: new THREE.Color(0x2a4a2a) },
    offset:  { value: 20 }, exponent: { value: 0.5 },
  },
  vertexShader:`
    varying vec3 vWP;
    void main(){ vWP=(modelMatrix*vec4(position,1.0)).xyz; gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0); }`,
  fragmentShader:`
    uniform vec3 topColor,bottomColor; uniform float offset,exponent; varying vec3 vWP;
    void main(){float h=normalize(vWP+vec3(0,offset,0)).y; gl_FragColor=vec4(mix(bottomColor,topColor,max(pow(max(h,0.0),exponent),0.0)),1.0);}`,
});
worldGroup.add(new THREE.Mesh(new THREE.SphereGeometry(100,48,48), skyMat));

/* ─── SOL ─── */
const gnd = new THREE.Mesh(
  new THREE.PlaneGeometry(60,60,80,80),
  new THREE.MeshStandardMaterial({ color:0x2a5a1a, roughness:0.9 })
);
gnd.rotation.x = -Math.PI/2; gnd.receiveShadow = true;
worldGroup.add(gnd);

const soil = new THREE.Mesh(
  new THREE.CircleGeometry(1.5,48),
  new THREE.MeshStandardMaterial({ color:0x3a2a1a, roughness:1 })
);
soil.rotation.x = -Math.PI/2; soil.position.set(0,0.01,0); soil.receiveShadow = true;
worldGroup.add(soil);

/* ─── HERBE INSTANCIÉE ─── */
const GRASS_N = 10000;
const grassGeo = new THREE.PlaneGeometry(0.08, 0.5, 1, 3);
grassGeo.translate(0, 0.25, 0);

const grassMat = new THREE.ShaderMaterial({
  uniforms:{ time:{value:0}, wind:{value:0.3} },
  vertexShader:`
    uniform float time,wind;
    attribute float phase,ht;
    varying float vH;
    void main(){
      vH=position.y/0.5;
      vec3 p=position;
      p.x+=sin(time*2.0+phase)*wind*p.y*p.y + cos(time*1.3+phase*0.7)*wind*0.5*p.y;
      p.z+=cos(time*1.7+phase*1.3)*wind*0.3*p.y;
      p.x*=(1.0-vH*0.6); p.z*=(1.0-vH*0.6);
      gl_Position=projectionMatrix*modelViewMatrix*instanceMatrix*vec4(p*vec3(1,ht,1),1.0);
    }`,
  fragmentShader:`
    varying float vH;
    void main(){
      vec3 c=mix(vec3(0.14,0.34,0.09),vec3(0.3,0.6,0.14),vH);
      c=mix(c,vec3(0.38,0.68,0.18),vH*vH*0.5);
      gl_FragColor=vec4(c*mix(0.5,1.0,vH),1.0);
    }`,
  side:THREE.DoubleSide,
});

const grassMesh = new THREE.InstancedMesh(grassGeo, grassMat, GRASS_N);
const _pha = new Float32Array(GRASS_N);
const _ht  = new Float32Array(GRASS_N);
const _d   = new THREE.Object3D();
for(let i=0;i<GRASS_N;i++){
  const a=Math.random()*Math.PI*2, r=Math.random()*24+2;
  _d.position.set(Math.cos(a)*r, 0, Math.sin(a)*r);
  _d.rotation.set(0, Math.random()*Math.PI, 0);
  _d.scale.set(0.8+Math.random()*0.5, 1, 1);
  _d.updateMatrix();
  grassMesh.setMatrixAt(i, _d.matrix);
  _pha[i] = Math.random()*Math.PI*2;
  _ht[i]  = 0.6+Math.random()*0.8;
}
grassGeo.setAttribute('phase', new THREE.InstancedBufferAttribute(_pha,1));
grassGeo.setAttribute('ht',    new THREE.InstancedBufferAttribute(_ht,1));
grassMesh.instanceMatrix.needsUpdate = true;
worldGroup.add(grassMesh);

/* ─── FLEURS ─── */
const fCols = [0xff6b9d,0xffd93d,0xc084fc,0xffffff,0xff8fab];
for(let i=0;i<34;i++){
  const a=Math.random()*Math.PI*2, r=3+Math.random()*18;
  const fg = new THREE.Group();
  const stem = new THREE.Mesh(
    new THREE.CylinderGeometry(0.01,0.01,0.2,4),
    new THREE.MeshStandardMaterial({color:0x2e7d32})
  );
  stem.position.y=0.1; fg.add(stem);
  const petal = new THREE.Mesh(
    new THREE.SphereGeometry(0.05,6,6),
    new THREE.MeshStandardMaterial({color:fCols[i%fCols.length]})
  );
  petal.position.y=0.22; fg.add(petal);
  fg.position.set(Math.cos(a)*r, 0, Math.sin(a)*r);
  worldGroup.add(fg);
}

/* ─── CAILLOUX ─── */
for(let i=0;i<20;i++){
  const a=Math.random()*Math.PI*2, r=2+Math.random()*14;
  const pg = new THREE.SphereGeometry(0.05+Math.random()*0.08,6,6);
  pg.scale(1, 0.5, 1+Math.random()*0.3);
  const pm = new THREE.Mesh(pg, new THREE.MeshStandardMaterial({
    color: new THREE.Color().setHSL(0.08,0.1,0.3+Math.random()*0.2), roughness:0.95
  }));
  pm.position.set(Math.cos(a)*r, 0.02, Math.sin(a)*r);
  worldGroup.add(pm);
}

/* ─── GRAINE ─── */
const seedGeo = new THREE.SphereGeometry(0.12,16,16);
seedGeo.scale(1, 0.7, 0.8); // scale sur la géométrie (method correcte)
const seed = new THREE.Mesh(seedGeo, new THREE.MeshStandardMaterial({color:0x8B6914,roughness:0.8}));
seed.position.set(0, 0.5, 3);
seed.castShadow = true; seed.visible = false;
worldGroup.add(seed);

/* ─── TROU ─── */
const hole = new THREE.Mesh(
  new THREE.CylinderGeometry(0.4,0.3,0.3,32),
  new THREE.MeshStandardMaterial({color:0x1a0f05,roughness:1})
);
hole.position.set(0,-0.15,0); hole.visible = false;
worldGroup.add(hole);

/* ─── ARBRE ─── */
const treeGroup = new THREE.Group();
worldGroup.add(treeGroup);
let treeObjs = [];

/* ─── LUCIOLES ─── */
const ffN = 28;
const ffGeo = new THREE.BufferGeometry();
const ffPos = new Float32Array(ffN*3);
const ffPha = new Float32Array(ffN);
for(let i=0;i<ffN;i++){
  ffPos[i*3]=(Math.random()-.5)*18; ffPos[i*3+1]=0.5+Math.random()*4; ffPos[i*3+2]=(Math.random()-.5)*18;
  ffPha[i]=Math.random()*Math.PI*2;
}
ffGeo.setAttribute('position',new THREE.BufferAttribute(ffPos,3));
const ffMat = new THREE.PointsMaterial({color:0xffee88,size:0.1,transparent:true,opacity:0.55});
worldGroup.add(new THREE.Points(ffGeo,ffMat));
const fireflies = worldGroup.children[worldGroup.children.length-1];

/* ─── ARROSOIR ─── */
const canGroup = new THREE.Group();
canGroup.visible = false;
const canMat = new THREE.MeshStandardMaterial({color:0x4a7a8a,roughness:0.5,metalness:0.3});
const canBody = new THREE.Mesh(new THREE.CylinderGeometry(0.25,0.3,0.5,12), canMat);
canGroup.add(canBody);
const spout = new THREE.Mesh(new THREE.CylinderGeometry(0.04,0.06,0.4,8), canMat);
spout.position.set(0.2,0.15,0); spout.rotation.z=-0.8;
canGroup.add(spout);
canGroup.position.set(1.5,3,2); canGroup.rotation.z=-0.3;
worldGroup.add(canGroup);

/* ─── PARTICULES EAU ─── */
let waterP = null;
let waterA = {active:false,time:0};

(function initWater(){
  const n=200, geo=new THREE.BufferGeometry();
  const pos=new Float32Array(n*3), vel=new Float32Array(n*3);
  for(let i=0;i<n;i++){
    pos[i*3]=(Math.random()-.5)*1.5; pos[i*3+1]=3+Math.random()*2; pos[i*3+2]=(Math.random()-.5)*1.5;
    vel[i*3]=(Math.random()-.5)*.02; vel[i*3+1]=-.05-Math.random()*.08; vel[i*3+2]=(Math.random()-.5)*.02;
  }
  geo.setAttribute('position',new THREE.BufferAttribute(pos,3));
  geo.userData.velocity=vel;
  waterP = new THREE.Points(geo, new THREE.PointsMaterial({color:0x4dc8ff,size:.06,transparent:true,opacity:.7}));
  waterP.visible=false;
  worldGroup.add(waterP); // dans worldGroup pour coïncider avec l'arbre en XR
})();

function startWaterAnim(){
  waterA={active:true,time:0}; waterP.visible=true;
  const pos=waterP.geometry.attributes.position;
  for(let i=0;i<pos.count;i++) pos.setXYZ(i,(Math.random()-.5)*1.5,3+Math.random()*2,(Math.random()-.5)*1.5);
  pos.needsUpdate=true;
}

/* ─── RETICLE AR ─── */
const reticle = new THREE.Mesh(
  new THREE.RingGeometry(0.15,0.2,32).rotateX(-Math.PI/2),
  new THREE.MeshBasicMaterial({color:0x00ffbf})
);
reticle.matrixAutoUpdate=false; reticle.visible=false;
scene.add(reticle);

/* ─── HAND TRACKING QUEST 3 ─── */
const XR_JOINTS = [
  'wrist',
  'thumb-metacarpal','thumb-phalanx-proximal','thumb-phalanx-distal','thumb-tip',
  'index-finger-metacarpal','index-finger-phalanx-proximal','index-finger-phalanx-intermediate','index-finger-phalanx-distal','index-finger-tip',
  'middle-finger-metacarpal','middle-finger-phalanx-proximal','middle-finger-phalanx-intermediate','middle-finger-phalanx-distal','middle-finger-tip',
  'ring-finger-metacarpal','ring-finger-phalanx-proximal','ring-finger-phalanx-intermediate','ring-finger-phalanx-distal','ring-finger-tip',
  'pinky-finger-metacarpal','pinky-finger-phalanx-proximal','pinky-finger-phalanx-intermediate','pinky-finger-phalanx-distal','pinky-finger-tip',
];

const jGeo = new THREE.SphereGeometry(0.007,6,6);
const jMat = new THREE.MeshStandardMaterial({color:0xe8c8a0,roughness:0.6});
const handMaps = [{},{}]; // joint name → Mesh, per hand
for(let h=0;h<2;h++){
  for(const name of XR_JOINTS){
    const m=new THREE.Mesh(jGeo,jMat);
    m.visible=false; scene.add(m);
    handMaps[h][name]=m;
  }
}
const dropCursor = new THREE.Mesh(
  new THREE.SphereGeometry(0.022,8,8),
  new THREE.MeshStandardMaterial({color:0x4dc8ff,transparent:true,opacity:0.82})
);
dropCursor.visible=false; scene.add(dropCursor);

const xrHand0 = renderer.xr.getHand(0);
const xrHand1 = renderer.xr.getHand(1);
scene.add(xrHand0); scene.add(xrHand1);

// AR controller pour placement
const arCtrl = renderer.xr.getController(0);
arCtrl.addEventListener('select',()=>{
  if(reticle.visible){ treeGroup.position.setFromMatrixPosition(reticle.matrix); treeGroup.updateMatrixWorld(true); }
});
scene.add(arCtrl);

let pinchWas0=false, pinchWas1=false, lastPinch=0;

function pinchDist(hand){
  const a=hand.joints?.['index-finger-tip'], b=hand.joints?.['thumb-tip'];
  return (a&&b&&a.jointRadius!==undefined&&b.jointRadius!==undefined)
    ? a.position.distanceTo(b.position) : Infinity;
}
function updateHandViz(hand, map, isRight){
  if(!hand.joints){ Object.values(map).forEach(m=>m.visible=false); if(isRight)dropCursor.visible=false; return; }
  for(const [n,m] of Object.entries(map)){
    const j=hand.joints[n];
    if(j&&j.jointRadius!==undefined){ m.visible=true; m.position.copy(j.position); m.quaternion.copy(j.quaternion); }
    else { m.visible=false; }
  }
  if(isRight){
    const tip=hand.joints['index-finger-tip'];
    if(tip&&tip.jointRadius!==undefined){
      dropCursor.visible=true; dropCursor.position.copy(tip.position); dropCursor.position.y-=0.03;
    } else { dropCursor.visible=false; }
  }
}

/* ─── XR BOUTONS CUSTOM ─── */
let xrSession=null;
async function initXR(){
  if(!navigator.xr) return;
  const c=document.getElementById('ygg-xr-btns');
  try{ if(await navigator.xr.isSessionSupported('immersive-vr')){ const b=mkXRBtn('🥽 VR',()=>enterXR('immersive-vr')); c.appendChild(b); } }catch(e){}
  try{ if(await navigator.xr.isSessionSupported('immersive-ar')){ const b=mkXRBtn('📷 AR',()=>enterXR('immersive-ar')); c.appendChild(b); } }catch(e){}
}
function mkXRBtn(label,fn){
  const b=document.createElement('button');
  b.className='ygg-xrbtn'; b.textContent=label; b.addEventListener('click',fn); return b;
}
async function enterXR(mode){
  if(xrSession){ try{await xrSession.end();}catch(e){} return; }
  const opts={
    requiredFeatures:['local-floor'],
    optionalFeatures:['hand-tracking', mode==='immersive-ar'?'hit-test':'bounded-floor'],
  };
  if(mode==='immersive-ar'){
    opts.optionalFeatures.push('dom-overlay');
    opts.domOverlay={root:document.getElementById('ygg-ui')};
  }
  try{
    const s=await navigator.xr.requestSession(mode,opts);
    xrSession=s; renderer.xr.setSession(s);
    s.addEventListener('end',()=>{ xrSession=null; worldGroup.position.set(0,0,0); updateCam(); });
    // Décale l'utilisateur à 5m de l'arbre (évite de spawner dans le tronc)
    try{
      const rs=await s.requestReferenceSpace('local-floor');
      const off=new XRRigidTransform({x:0,y:0,z:-5,w:1});
      renderer.xr.setReferenceSpace(rs.getOffsetReferenceSpace(off));
    }catch(e){ worldGroup.position.z=-5; }
  }catch(err){ console.warn('XR failed:',err); }
}

let hitSrc=null, hitSrcReq=false;

/* ─── CAMÉRA ORBITE (desktop/mobile) ─── */
let drag=false, pmx=0, pmy=0, azimuth=0, polar=0.5, camR=12;
function updateCam(){
  if(renderer.xr.isPresenting) return;
  camera.position.set(camR*Math.sin(polar)*Math.cos(azimuth), camR*Math.cos(polar), camR*Math.sin(polar)*Math.sin(azimuth));
  camera.lookAt(0,2,0);
}
updateCam();

/* ─── LOGIQUE JEU ─── */
const getStage = g => { let s=STAGES[0]; for(const st of STAGES) if(g>=st.min) s=st; return s; };
const fmtW = l => l<1?`${(l*1000).toFixed(0)} mL`:`${l.toFixed(1)} L`;
const wEq  = l => { const s=(l/SHOWER_LPM)*60; return s<60?`≈ ${s.toFixed(0)}s de douche`:`≈ ${(s/60).toFixed(1)}min de douche`; };
const rEco = () => ECO_FACTS[Math.floor(Math.random()*ECO_FACTS.length)];

function addJournal(txt){
  const d=new Date(), t=`${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
  gs.journal.unshift({time:t,text:txt});
  if(gs.journal.length>50) gs.journal.pop();
  save(); renderJournal();
}
function renderJournal(){
  document.getElementById('ygg-journal').innerHTML =
    gs.journal.map(e=>`<div class="ygg-entry"><span class="ygg-etime">${e.time}</span> ${e.text}</div>`).join('');
}

function showEco(title,text,dur=6000){
  const el=document.getElementById('ygg-eco-msg');
  el.innerHTML=`<span class="ygg-etitle">${title}</span>${text}`;
  el.classList.add('vis');
  clearTimeout(el._t); el._t=setTimeout(()=>el.classList.remove('vis'),dur);
}

function updateUI(){
  const st=getStage(gs.growth);
  document.getElementById('ygg-growth-val').textContent = `${Math.floor(gs.growth)}%`;
  document.getElementById('ygg-stage-name').textContent = st.name;
  document.getElementById('ygg-water-val').textContent  = fmtW(gs.totalWater);
  document.getElementById('ygg-water-eq').textContent   = wEq(gs.totalWater);
  if(gs.lastWaterTime){
    const mn=Math.floor((Date.now()-gs.lastWaterTime)/60000);
    const hr=Math.floor(mn/60), dy=Math.floor(hr/24);
    const ts=mn<1?"à l'instant":dy>0?`il y a ${dy}j`:hr>0?`il y a ${hr}h`:`il y a ${mn}min`;
    document.getElementById('ygg-water-eq').textContent=ts;
  }
}

/* ─── MODE AFFICHAGE ─── */
function setDisplayMode(color){
  isColor=color;
  const btn=document.getElementById('ygg-toggle-btn');
  btn.setAttribute('aria-checked', color?'true':'false');
  btn.classList.toggle('ygg-on', color);

  const logoImg  = document.getElementById('ygg-logo-img');
  const introLgo = document.getElementById('ygg-intro-logo');
  const togLgo   = document.getElementById('ygg-toggle-logo');

  if(color){
    canvas.classList.remove('ygg-nb');
    renderer.toneMappingExposure=1.1;
    skyMat.uniforms.topColor.value.set(0x0a1628);
    skyMat.uniforms.bottomColor.value.set(0x2a4a2a);
    logoImg.src=LOGO_GRADIENT; logoImg.classList.remove('ygg-nb-logo');
    introLgo.src=LOGO_GRADIENT; introLgo.classList.add('ygg-color-logo');
    togLgo.src=LOGO_GRADIENT;
    const cv=document.getElementById('ygg-cons-val');
    cv.classList.add('rich');
    animateCons(cv,CONS_RICH);
    document.getElementById('ygg-cons-desc').textContent='Mode Riche Actif : Empreinte Graphique Maximale';
    document.getElementById('ygg-cons-icon').textContent='💻';
  } else {
    canvas.classList.add('ygg-nb');
    renderer.toneMappingExposure=0.75;
    skyMat.uniforms.topColor.value.set(0x0d1520);
    skyMat.uniforms.bottomColor.value.set(0x1e2a1e);
    logoImg.src=LOGO_STROKE; logoImg.classList.add('ygg-nb-logo');
    introLgo.src=LOGO_STROKE; introLgo.classList.remove('ygg-color-logo');
    togLgo.src=LOGO_MAIN;
    const cv=document.getElementById('ygg-cons-val');
    cv.classList.remove('rich');
    animateCons(cv,CONS_ECO);
    document.getElementById('ygg-cons-desc').textContent='Mode Éco Actif : Empreinte Graphique Minimale';
    document.getElementById('ygg-cons-icon').textContent='🪣';
  }
}

function animateCons(el,target){
  const from=parseFloat(el.textContent)||0, t0=performance.now();
  (function step(now){
    const p=Math.min((now-t0)/800,1), e=p<.5?2*p*p:-1+(4-2*p)*p;
    el.textContent=(from+(target-from)*e).toFixed(1)+' mL/s';
    if(p<1) requestAnimationFrame(step);
  })(t0);
}

/* ─── CONSTRUCTION ARBRE ─── */
function buildTree(growth){
  treeObjs.forEach(o=>{
    treeGroup.remove(o);
    o.geometry?.dispose();
    (Array.isArray(o.material)?o.material:[o.material]).forEach(m=>m?.dispose());
  });
  treeObjs=[];
  if(growth<=0) return;
  const t=growth/100, trunkH=0.3+t*8, trunkR=0.05+t*0.6;
  const trunkCol=growth>=90?0x4a3a2a:0x3a2a1a;

  const tGeo=new THREE.CylinderGeometry(trunkR*.6,trunkR,trunkH,20,12);
  const tp=tGeo.attributes.position;
  for(let i=0;i<tp.count;i++) tp.setX(i,tp.getX(i)+Math.sin(tp.getY(i)/trunkH*2)*t*.3);
  tGeo.computeVertexNormals();
  const trunk=new THREE.Mesh(tGeo,new THREE.MeshStandardMaterial({color:trunkCol,roughness:.9}));
  trunk.position.y=trunkH/2; trunk.castShadow=true;
  treeGroup.add(trunk); treeObjs.push(trunk);

  if(growth>30){
    let fi=Math.max(0,Math.floor((growth-30)/10)); if(fi>=FIB.length) fi=FIB.length-1;
    for(let i=0;i<FIB[fi];i++){
      const ang=i*GOLDEN_ANGLE+Math.random()*.2;
      const bH=.5+t*3*(.5+Math.random()*.5), bR=.02+t*.15, bY=trunkH*(.4+(i/FIB[fi])*.5);
      const b=new THREE.Mesh(new THREE.CylinderGeometry(bR*.3,bR,bH,10),
        new THREE.MeshStandardMaterial({color:trunkCol,roughness:.9}));
      b.position.set(Math.cos(ang)*trunkR*.8,bY,Math.sin(ang)*trunkR*.8);
      b.rotation.z=(Math.cos(ang)>0?-1:1)*(.4+Math.random()*.6); b.rotation.y=ang;
      b.castShadow=true; treeGroup.add(b); treeObjs.push(b);
    }
  }

  if(growth>10){
    const layers=growth>=90?5:(growth>=50?3:1);
    const leafCol=growth>=90?0xd4af37:(growth>=70?0x1a6b1a:0x2e8b2e);
    for(let l=0;l<layers;l++){
      const cR=(.3+t*3.5)*(1-l*.15), cY=trunkH*.7+l*trunkH*.15;
      const cGeo=new THREE.SphereGeometry(cR,26,16);
      const cp=cGeo.attributes.position;
      for(let i=0;i<cp.count;i++){const n=.82+Math.random()*.36; cp.setXYZ(i,cp.getX(i)*n,cp.getY(i)*n,cp.getZ(i)*n);}
      cGeo.computeVertexNormals();
      const c=new THREE.Mesh(cGeo,new THREE.MeshStandardMaterial({color:leafCol,roughness:.8,metalness:growth>=90?.2:0}));
      c.name=`canopy_${l}`; c.position.set(Math.sin(l*GOLDEN_ANGLE)*.3,cY,Math.cos(l*GOLDEN_ANGLE)*.3);
      c.castShadow=true; treeGroup.add(c); treeObjs.push(c);
    }
    if(growth>=90){
      for(let i=0;i<8;i++){
        const ra=(i/8)*Math.PI*2, rl=2+Math.random()*2;
        const r=new THREE.Mesh(new THREE.CylinderGeometry(.05,.2,rl,10),
          new THREE.MeshStandardMaterial({color:0x3a2a1a,roughness:1}));
        r.position.set(Math.cos(ra)*rl*.4,.1,Math.sin(ra)*rl*.4); r.rotation.z=Math.cos(ra)*1.2; r.rotation.y=ra;
        treeGroup.add(r); treeObjs.push(r);
      }
      const gGeo=new THREE.BufferGeometry();
      const gp=new Float32Array(50*3);
      for(let i=0;i<50;i++){gp[i*3]=(Math.random()-.5)*6;gp[i*3+1]=2+Math.random()*(trunkH*.8);gp[i*3+2]=(Math.random()-.5)*6;}
      gGeo.setAttribute('position',new THREE.BufferAttribute(gp,3));
      const gpts=new THREE.Points(gGeo,new THREE.PointsMaterial({color:0xffd700,size:.15,transparent:true,opacity:.6}));
      gpts.name='yggGlow'; treeGroup.add(gpts); treeObjs.push(gpts);
    }
  }
}

/* ─── ARROSAGE ─── */
function doWatering(){
  const now=Date.now(), mins=gs.lastWaterTime?(now-gs.lastWaterTime)/60000:Infinity;
  const used=WATER_ARR+gs.pageWater;
  gs.totalWater+=used; gs.pageWater=0; gs.waterCount++; gs.lastWaterTime=now;

  let gain=0;
  if(gs.phase==='firstWater'){
    gain=5; addJournal(`💧 Premier arrosage ! ${fmtW(used)}.`);
  } else if(mins<1){
    gain=.5; gs.overwatered=true;
    addJournal(`⚠️ Trop fréquent. ${fmtW(used)} gaspillés.`);
    showEco('⚠️ Trop d\'eau !',`${fmtW(used)} utilisés — l'arbre n'en avait pas besoin.<br>${rEco()}`);
  } else if(mins<5){
    gain=2; addJournal(`💧 Arrosage. ${fmtW(used)}.`);
    showEco('💧 Arrosage',`${fmtW(used)} (${wEq(used)}). ${rEco()}`);
  } else if(mins<60){
    gain=5; addJournal(`💧 Bon arrosage ! ${fmtW(used)}.`);
    showEco('🌿 Bon timing !',`L'arbre apprécie un arrosage espacé. ${fmtW(used)}. ${rEco()}`);
  } else {
    gain=10+Math.min(mins/120,10);
    addJournal(`🌟 Arrosage patient ! ${fmtW(used)}.`);
    showEco('🌟 Vertueux !',`Ta patience est récompensée ! Croissance bonus. ${rEco()}`);
  }

  gs.growth=Math.min(100,gs.growth+gain);
  startWaterAnim();
  canGroup.visible=true;
  setTimeout(()=>{canGroup.visible=false;},3000);
  buildTree(gs.growth);

  if(gs.phase==='firstWater'){
    setPhase('growing');
    showEco('🌱 Germination !',`Ta graine germe ! ${fmtW(used)} utilisés (dont ${fmtW(WATER_PAGE)} à l'ouverture). ${rEco()}`);
  }
  if(gs.growth>=90&&gs.phase!=='yggdrasil'){
    setPhase('yggdrasil');
    addJournal('🌳✨ Ton arbre est devenu YGGDRASIL !');
    showEco('✨ YGGDRASIL ✨',`Forme ultime ! ${fmtW(gs.totalWater)} utilisés. Clique 📖 pour réfléchir.`,9000);
  }
  save(); updateUI();
  // Flash pinch XR
  const fl=document.getElementById('ygg-pinch-flash');
  fl.classList.add('fl'); setTimeout(()=>fl.classList.remove('fl'),180);
}

/* ─── PHASES ─── */
let digA={active:false,time:0}, plantA={active:false,time:0}, coverA={active:false,time:0};

/* Utilitaire : montre/cache les boutons sans conflit !important */
function showBtns(...ids){ ['dig','plant','cover','water','moral'].forEach(id=>{ const b=document.getElementById(`ygg-btn-${id}`); if(b) b.style.display=ids.includes(id)?'flex':'none'; }); }

function setPhase(phase){
  gs.phase=phase; save();
  const showHUD=!['start','digging','planting','covering'].includes(phase);
  document.getElementById('ygg-hud').style.display       = showHUD?'flex':'none';
  document.getElementById('ygg-active-cons').style.display = showHUD?'flex':'none';
  document.getElementById('ygg-journal').style.display    = showHUD?'block':'none';
  if(showHUD) renderJournal();

  switch(phase){
    case 'start':
      seed.visible=true; seed.position.set(0,.5,3); seed.scale.setScalar(1);
      showBtns('dig'); break;
    case 'digging':
      showBtns(); digA={active:true,time:0}; break;
    case 'planting':
      seed.visible=true; seed.position.set(0,.5,3); seed.scale.setScalar(1);
      showBtns('plant'); break;
    case 'covering':
      showBtns('cover'); break;
    case 'firstWater':
      showBtns('water'); break;
    case 'growing':
    case 'yggdrasil':
      showBtns('water','moral');
      buildTree(gs.growth); break;
  }
  updateUI();
}

function showMoral(){
  document.getElementById('ygg-moral').hidden=false;
  const tw=gs.totalWater, pw=gs.pageLoads*WATER_PAGE;
  document.getElementById('ygg-moral-text').innerHTML=`
    Ton arbre est magnifique. Chaque visite consomme <strong>${fmtW(WATER_PAGE)}</strong> symboliquement,
    et chaque arrosage <strong>${fmtW(WATER_ARR)}</strong> de plus.<br><br>
    <em>Les datacenters d'Internet consomment des milliards de litres pour leur refroidissement. Chaque pixel compte.</em>`;
  document.getElementById('ygg-moral-stat').innerHTML=
    `💧 Total : ${fmtW(tw)}<br>🌱 Dont ${fmtW(pw)} en ouvrant la page ${gs.pageLoads}×<br>🚿 ${wEq(tw)}`;
  document.getElementById('ygg-moral-advice').innerHTML=
    `<strong>La morale :</strong> Le meilleur joueur n'est pas celui qui a le plus gros arbre —
     c'est celui qui a utilisé le <em>moins d'eau</em> pour y arriver.<br><br>
     <strong style="color:#9de090;">Score écologique : ${Math.max(0,100-Math.floor(tw*2))}/100</strong>`;
}

/* ─── DÉMARRAGE DU JEU ─── */
function startGame(){
  const intro=document.getElementById('ygg-intro');
  intro.classList.add('ygg-out');
  setTimeout(()=>{ intro.style.display='none'; },1200);

  document.getElementById('ygg-actions').style.display='flex';
  document.getElementById('ygg-toggle-bar').style.display='flex';

  setDisplayMode(false); // N&B par défaut

  setPhase(gs.phase);

  if(gs.phase==='start'){
    showEco('🌰 Ta graine','Tu as une graine. Creuse un trou dans le sol pour la planter.');
  }
  if(['growing','yggdrasil'].includes(gs.phase)){
    setTimeout(()=>showEco('🌱 Connexion détectée',
      `Rien qu'en ouvrant cette page, <strong>${fmtW(WATER_PAGE)}</strong> dépensés. ${rEco()}`), 1500);
  }
}

/* ─── EVENT LISTENERS ─── */
document.getElementById('ygg-start-btn').addEventListener('click', startGame);

document.getElementById('ygg-reset-btn').addEventListener('click',()=>{
  localStorage.removeItem(SAVE_KEY); location.reload();
});

document.getElementById('ygg-toggle-btn').addEventListener('click',()=> setDisplayMode(!isColor));

document.getElementById('ygg-btn-dig').addEventListener('click',()=>{
  setPhase('digging'); addJournal('🤲 Tu creuses un trou dans la terre...');
});
document.getElementById('ygg-btn-plant').addEventListener('click',()=>{
  setPhase('covering'); plantA={active:true,time:0};
  addJournal('🌰 Tu déposes la graine au creux de la terre.');
});
document.getElementById('ygg-btn-cover').addEventListener('click',()=>{
  coverA={active:true,time:0};
  addJournal('🫳 Tu recouvres doucement la graine de terre.');
  setTimeout(()=>{
    setPhase('firstWater');
    showEco('🌱 Première étape','Ta graine est plantée. Elle a besoin de son premier arrosage pour germer.');
  },1800);
});
document.getElementById('ygg-btn-water').addEventListener('click', doWatering);
document.getElementById('ygg-btn-moral').addEventListener('click', showMoral);
document.getElementById('ygg-close-moral').addEventListener('click',()=>{ document.getElementById('ygg-moral').hidden=true; });

// Bouton i
const infoBtn=document.getElementById('ygg-info-btn');
const helpPanel=document.getElementById('ygg-help-panel');
infoBtn.addEventListener('click',()=>{
  const h=helpPanel.hidden; helpPanel.hidden=!h; infoBtn.setAttribute('aria-expanded',h?'true':'false');
});
document.getElementById('ygg-help-close').addEventListener('click',()=>{ helpPanel.hidden=true; infoBtn.setAttribute('aria-expanded','false'); });

// Orbite souris
canvas.addEventListener('pointerdown',e=>{drag=true;pmx=e.clientX;pmy=e.clientY;});
canvas.addEventListener('pointerup',()=>drag=false);
canvas.addEventListener('pointerleave',()=>drag=false);
canvas.addEventListener('pointermove',e=>{
  if(!drag) return;
  azimuth-=(e.clientX-pmx)*.005; polar=Math.max(.08,Math.min(Math.PI/2-.05,polar-(e.clientY-pmy)*.005));
  pmx=e.clientX; pmy=e.clientY; updateCam();
});

// Zoom molette
window.addEventListener('wheel',e=>{
  e.preventDefault(); camR=Math.max(4,Math.min(28,camR+e.deltaY*.01)); updateCam();
},{passive:false});

// Zoom tactile
let ltd=0;
canvas.addEventListener('touchstart',e=>{ if(e.touches.length===2) ltd=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY); });
canvas.addEventListener('touchmove',e=>{
  if(e.touches.length===2){
    e.preventDefault();
    const d=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY);
    camR=Math.max(4,Math.min(28,camR-(d-ltd)*.05)); ltd=d; updateCam();
  }
},{passive:false});

// Reset keyboard
window.addEventListener('keydown',e=>{ if(e.key==='r'&&e.ctrlKey&&e.shiftKey){localStorage.removeItem(SAVE_KEY);location.reload();} });

// Resize
window.addEventListener('resize',()=>{
  camera.aspect=window.innerWidth/window.innerHeight; camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth,window.innerHeight); updateCam();
});

/* ─── INIT ─── */
if(gs.phase!=='start') document.getElementById('ygg-start-btn').textContent='Retrouver mon arbre';
// Logo intro N&B par défaut (fond sombre → inversion)
document.getElementById('ygg-intro-logo').src=LOGO_STROKE;
document.getElementById('ygg-logo-img').src=LOGO_STROKE;
canvas.classList.add('ygg-nb');
initXR();

/* ─── BOUCLE ANIMATION ─── */
const clock=new THREE.Clock();

renderer.setAnimationLoop((timestamp, frame)=>{
  const dt=clock.getDelta(), t=clock.elapsedTime;

  /* Herbe */
  grassMat.uniforms.time.value=t;

  /* Lucioles */
  const fp=ffGeo.attributes.position;
  for(let i=0;i<ffN;i++){
    fp.setY(i,fp.getY(i)+Math.sin(t*.5+ffPha[i])*.002);
    fp.setX(i,fp.getX(i)+Math.cos(t*.3+ffPha[i])*.001);
  }
  fp.needsUpdate=true;
  ffMat.opacity=.3+Math.sin(t*2)*.24;

  /* Graine flottante */
  if(seed.visible&&gs.phase==='start'){
    seed.position.y=.5+Math.sin(t*2)*.05; seed.rotation.y=t*.5;
  }

  /* Phase : creuser */
  if(digA.active){
    digA.time+=dt*1.2; const p=Math.min(digA.time,1);
    if(p>=1){ digA.active=false; hole.visible=true; setPhase('planting'); showEco('🕳️ Trou creusé','Le sol est prêt. Plante ta graine !'); }
  }

  /* Phase : planter */
  if(plantA.active){
    plantA.time+=dt*1.2; const p=Math.min(plantA.time,1);
    seed.position.set(0,.5-p*.6,3-p*3); seed.scale.setScalar(1-p*.3);
    if(p>=1){ plantA.active=false; seed.visible=false; }
  }

  /* Phase : recouvrir */
  if(coverA.active){
    coverA.time+=dt*.9; const p=Math.min(coverA.time,1);
    hole.scale.y=1-p;
    if(p>=1){ coverA.active=false; hole.visible=false; hole.scale.y=1; }
  }

  /* Eau */
  if(waterA.active){
    waterA.time+=dt;
    const pos=waterP.geometry.attributes.position, vel=waterP.geometry.userData.velocity;
    for(let i=0;i<pos.count;i++){
      pos.setX(i,pos.getX(i)+vel[i*3]); pos.setY(i,pos.getY(i)+vel[i*3+1]); pos.setZ(i,pos.getZ(i)+vel[i*3+2]);
      vel[i*3+1]-=.001;
      if(pos.getY(i)<0){ pos.setXYZ(i,(Math.random()-.5)*1.5,3+Math.random(),(Math.random()-.5)*1.5); vel[i*3+1]=-.05-Math.random()*.08; }
    }
    pos.needsUpdate=true;
    if(waterA.time>3){ waterA.active=false; waterP.visible=false; }
  }

  /* Arrosoir */
  if(canGroup.visible){ canGroup.position.y=3+Math.sin(t*3)*.1; canGroup.rotation.z=-.3-Math.sin(t*2)*.1; }

  /* Canopées ondulantes */
  treeGroup.rotation.y=Math.sin(t*.28)*.018;
  treeObjs.forEach(o=>{ if(o.name?.startsWith('canopy')) o.position.x+=Math.sin(t*.8+o.id)*.0007; });
  const glow=treeGroup.getObjectByName('yggGlow');
  if(glow){ glow.rotation.y=t*.1; glow.material.opacity=.3+Math.sin(t)*.3; }

  /* ─── HAND TRACKING XR ─── */
  if(renderer.xr.isPresenting){
    updateHandViz(xrHand0,handMaps[0],false);
    updateHandViz(xrHand1,handMaps[1],true);

    const d0=pinchDist(xrHand0), isPinch0=d0<.03;
    if(isPinch0&&!pinchWas0){
      const now=Date.now();
      if(now-lastPinch>2000&&['firstWater','growing','yggdrasil'].includes(gs.phase)){ lastPinch=now; doWatering(); }
    }
    pinchWas0=isPinch0;

    const d1=pinchDist(xrHand1), isPinch1=d1<.03;
    if(isPinch1&&!pinchWas1){
      const now=Date.now();
      if(now-lastPinch>2000&&['firstWater','growing','yggdrasil'].includes(gs.phase)){ lastPinch=now; doWatering(); }
    }
    pinchWas1=isPinch1;

    if(dropCursor){
      dropCursor.material.opacity=(isPinch0||isPinch1)?1:.8;
      dropCursor.scale.setScalar((isPinch0||isPinch1)?1.4:1);
    }

    /* AR Hit Test */
    if(frame){
      const refSpace=renderer.xr.getReferenceSpace(), sess=renderer.xr.getSession();
      if(!hitSrcReq&&sess){
        sess.requestReferenceSpace('viewer').then(vs=>
          sess.requestHitTestSource({space:vs}).then(s=>{ hitSrc=s; })
        );
        sess.addEventListener('end',()=>{ hitSrcReq=false; hitSrc=null; reticle.visible=false; });
        hitSrcReq=true;
      }
      if(hitSrc){
        const res=frame.getHitTestResults(hitSrc);
        if(res.length>0){ reticle.visible=true; reticle.matrix.fromArray(res[0].getPose(refSpace).transform.matrix); }
        else { reticle.visible=false; }
      }
    }
  } else {
    handMaps.forEach(m=>Object.values(m).forEach(mesh=>mesh.visible=false));
    if(dropCursor) dropCursor.visible=false;
    updateCam();
  }

  renderer.render(scene,camera);
});
</script>
</body>
</html>
				</div>
				</div>
					</div>
				</div>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/yggdrasil/">Yggdrasil</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>//*</title>
		<link>https://presentcomposedesign.fr/36446-2/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 19 Apr 2026 23:40:28 +0000</pubDate>
				<category><![CDATA[[ia]]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=36446</guid>

					<description><![CDATA[<p>YGGDRASIL — PCdlab 2026 Yggdrasil Plante un arbre. Nourris-le. Sauve la planète. Commencer Nouvelle partie 🌿 Croissance 0% Graine 💧 Eau utilisée 0 L &#160; 🪣 5.2 mL/s Mode Éco Actif : Empreinte Graphique Minimale SOBRIÉTÉ ÉCO (N&#38;B) 5.2 mL/s RICHE COULEUR (DÉTAIL) 87.6 mL/s 🤲 Creuser 🌰 Planter 🫳 Recouvrir 💧 Arroser 📖 Réfléchir i × 🌳 YGGDRASIL — PCdlab 2026 Souris / Clavier 🖱️ Glisser → Orbiter autour de l&#8217;arbre ⚙️ Molette → Zoom avant / arrière Ctrl+Maj+R → Réinitialiser la partie Tactile 👆 1 doigt glissé → Orbiter 🤏 2 doigts pincés → Zoom Quest 3 — Hand Tracking ✊ Pincer (index+pouce) → Arroser 🤚 Mains visibles → Curseur goutte 3D AR → Placer l&#8217;arbre dans l&#8217;espace réel Mode Affichage 🌑 Sobriété N&#038;B = 5.2 mL/s 🌈 Riche Couleur = 87.6 mL/s PCdlab 2026 · PrésentComposédesignCode : Claude Sonnet × Anthropic 📖 La Vérité sur ton Arbre Je comprends 🌱</p>
<p>Cet article <a href="https://presentcomposedesign.fr/36446-2/">//*</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="36446" class="elementor elementor-36446">
				<div class="elementor-element elementor-element-cbb3427 e-con-full e-flex wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="cbb3427" data-element_type="container" data-e-type="container">
				<div class="elementor-element elementor-element-d905f2b elementor-widget elementor-widget-html" data-id="d905f2b" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!--
╔══════════════════════════════════════════════════════════════════════════════════════════╗
║  YGGDRASIL — Plante ton arbre, sauve la planète                                          ║
║  PCdlab 2026 · PrésentComposédesign × Claude Sonnet (Anthropic)                          ║
╚══════════════════════════════════════════════════════════════════════════════════════════╝

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+#@@@@@@%. :%@@@@@@*+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.  .#@@@*     *@@@*.  =@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@@@@@@@@:    #@*       *@#    +@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.  -#%@@@@@@-   #%=       +%#   -@@@@@@%*:  .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.     .@@@@@@%*+%%    @   :%%++%@@@@@@.     .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@*    #@@.      .%@%   =%@@*   @   *@@%-   @@#.      .@@#    *@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@=    -@#   ::  -@%     -@%:  @  :%@-     %@-  =.   %@-    *@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@%%   *@%    # -@%       @%-:@:-%@       %%: %   :%@+   %%@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@**=+**#@@@@@@+::%#@@   :.  :@@@@@@@:  ..   @@@@.:+@@@@@@#***+*#@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@=       :#@@@%*%%@@@@.  += :@@@@@@@: -=  .@@@@@%+@@@@#:       %@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@:     .%%          @@-     *@@*     =@@         *@%      -@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@=      *%-    :=: .@+        #@@@@@%:   :%@@@@@#       .*%. :=:    +@- .    =@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@+.  :*@@#+    :@*%@:        +@@@#.     .#@@@+        :@#*@:    *#@@@:   +%@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@%%%%%%@@@@@@@@@@@@@@@@    :=  -%@%        :%@#:  =.    @@@@@%%@@@@@@@@@%%%%%%@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  ╭─────────────────────────────────────────────────────────────╮
  │  ░░░ CLAUDE SONNET — Anthropic AI ░░░                       │
  │  Code : PCdlab 2026 — WebXR / Three.js / Quest 3            │
  │  Fix : display !important override · Hand Tracking           │
  ╰─────────────────────────────────────────────────────────────╯
-->
<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="theme-color" content="#0a1008">
  <title>YGGDRASIL — PCdlab 2026</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
  <style>
    /* ═══════════════════════════════════════════════════════════════
       YGGDRASIL — CSS ISOLATION WORDPRESS / ELEMENTOR / ROYAL ADDONS
       ─ Tous les sélecteurs scoped sous #ygg-pcdb-root
       ─ !important uniquement sur les props de LAYOUT (jamais sur display
         des éléments contrôlés par JS → sinon le JS ne peut plus les cacher)
       ═══════════════════════════════════════════════════════════════ */

    html, body { margin: 0 !important; padding: 0 !important; overflow: hidden !important; }

    /* ─── ROOT ─── */
    #ygg-pcdb-root {
      position: fixed !important;
      inset: 0 !important;
      width: 100% !important; height: 100% !important;
      overflow: hidden !important;
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
      font-size: 14px !important; line-height: 1.5 !important;
      background: #0a1008 !important;
      z-index: 99998 !important;
      box-sizing: border-box !important;
    }
    #ygg-pcdb-root *, #ygg-pcdb-root *::before, #ygg-pcdb-root *::after {
      box-sizing: border-box !important;
      margin: 0 !important; padding: 0 !important;
      /* PAS de border:none ici — on le met par sélecteur précis */
      font-family: inherit !important;
      -webkit-tap-highlight-color: transparent !important;
    }

    /* ─── CANVAS ─── */
    #ygg-pcdb-root #ygg-canvas {
      position: absolute !important;
      inset: 0 !important; display: block !important;
      width: 100% !important; height: 100% !important;
      z-index: 1 !important;
      transition: filter 0.9s ease !important;
    }
    #ygg-pcdb-root #ygg-canvas.ygg-nb {
      filter: grayscale(1) contrast(1.06) brightness(0.95) !important;
    }

    /* ─── UI LAYER ─── */
    #ygg-pcdb-root #ygg-ui {
      position: absolute !important; inset: 0 !important;
      z-index: 10 !important; pointer-events: none !important;
    }
    #ygg-pcdb-root #ygg-ui > * { pointer-events: auto !important; }

    /* ─── CARD ─── */
    #ygg-pcdb-root .ygg-card {
      background: rgba(8,14,8,0.85) !important;
      backdrop-filter: blur(14px) !important; -webkit-backdrop-filter: blur(14px) !important;
      border: 1px solid rgba(100,160,80,0.28) !important;
      border-radius: 10px !important; padding: 10px 14px !important;
      color: #c8dfc0 !important; font-size: 12px !important;
      pointer-events: auto !important;
    }
    #ygg-pcdb-root .ygg-lbl {
      font-size: 9px !important; text-transform: uppercase !important;
      letter-spacing: 1.3px !important; color: rgba(130,185,110,0.55) !important;
      margin-bottom: 3px !important; display: block !important;
    }
    #ygg-pcdb-root .ygg-val {
      font-size: 18px !important; font-weight: 600 !important;
      color: #9de090 !important; font-family: 'Playfair Display', Georgia, serif !important;
      display: block !important;
    }
    #ygg-pcdb-root .ygg-val.blue { color: #7ec8e3 !important; }
    #ygg-pcdb-root .ygg-sub {
      font-size: 10px !important; color: rgba(150,195,130,0.45) !important;
      margin-top: 2px !important; display: block !important;
    }

    /* ─── HUD ─── */
    #ygg-pcdb-root #ygg-hud {
      position: absolute !important;
      top: 12px !important; left: 12px !important; right: 12px !important;
      display: none; /* contrôlé par JS — PAS de !important */
      justify-content: space-between !important; align-items: flex-start !important;
      z-index: 20 !important; pointer-events: none !important;
    }
    #ygg-pcdb-root #ygg-hud > * { pointer-events: auto !important; }
    #ygg-pcdb-root #ygg-growth-card { max-width: 195px !important; }
    #ygg-pcdb-root #ygg-water-card  { max-width: 195px !important; text-align: right !important; }

    /* ─── LOGO CENTRE ─── */
    #ygg-pcdb-root #ygg-logo-center { text-align: center !important; pointer-events: none !important; }
    #ygg-pcdb-root #ygg-logo-img {
      width: 68px !important; height: 68px !important; object-fit: contain !important;
      transition: filter 0.8s ease !important;
      filter: drop-shadow(0 0 8px rgba(80,180,80,0.35)) !important;
    }
    /* Logo N&B : inversion pour fond sombre */
    #ygg-pcdb-root #ygg-logo-img.ygg-nb-logo {
      filter: brightness(0) invert(1) opacity(0.85) !important;
    }
    #ygg-pcdb-root #ygg-intro-logo {
      width: 110px !important; height: 110px !important; object-fit: contain !important;
      margin-bottom: 22px !important;
      animation: ygg-float 3.2s ease-in-out infinite !important;
      /* Logo intro en N&B : inversion pour fond sombre */
      filter: brightness(0) invert(1) opacity(0.9) !important;
    }
    #ygg-pcdb-root #ygg-intro-logo.ygg-color-logo {
      filter: drop-shadow(0 0 18px rgba(80,200,80,0.35)) !important;
    }

    /* ─── TOGGLE BAR ─── */
    #ygg-pcdb-root #ygg-toggle-bar {
      position: absolute !important;
      bottom: 80px !important; left: 50% !important;
      transform: translateX(-50%) !important;
      display: none; /* contrôlé par JS */
      align-items: center !important; gap: 14px !important;
      background: rgba(6,10,6,0.9) !important;
      backdrop-filter: blur(14px) !important; -webkit-backdrop-filter: blur(14px) !important;
      border: 1px solid rgba(100,160,80,0.22) !important;
      border-radius: 14px !important; padding: 10px 18px !important;
      z-index: 20 !important; white-space: nowrap !important;
    }
    #ygg-pcdb-root .ygg-tside {
      display: flex !important; flex-direction: column !important;
      align-items: center !important; gap: 3px !important;
    }
    #ygg-pcdb-root .ygg-tlabel {
      font-size: 9px !important; text-transform: uppercase !important;
      letter-spacing: 1px !important; color: rgba(130,185,110,0.5) !important;
    }
    #ygg-pcdb-root .ygg-cdisp {
      font-size: 13px !important; font-weight: 700 !important;
      font-family: 'Playfair Display', Georgia, serif !important;
    }
    #ygg-pcdb-root .ygg-cdisp.eco { color: #7ec8a0 !important; }
    #ygg-pcdb-root .ygg-cdisp.rich { color: #e07c4a !important; }
    #ygg-pcdb-root .ygg-cunit {
      font-size: 9px !important; font-weight: 400 !important;
      font-family: 'Inter', sans-serif !important; opacity: 0.7 !important;
    }
    /* Toggle switch */
    #ygg-pcdb-root #ygg-toggle-btn {
      position: relative !important;
      width: 52px !important; height: 28px !important;
      background: rgba(30,50,30,0.8) !important;
      border: 1.5px solid rgba(100,160,80,0.5) !important;
      border-radius: 14px !important; cursor: pointer !important;
      flex-shrink: 0 !important; transition: background 0.4s !important;
    }
    #ygg-pcdb-root #ygg-toggle-btn.ygg-on {
      background: rgba(100,45,10,0.8) !important;
      border-color: rgba(200,120,60,0.5) !important;
    }
    #ygg-pcdb-root #ygg-toggle-thumb {
      position: absolute !important;
      width: 22px !important; height: 22px !important;
      top: 2px !important; left: 2px !important;
      background: rgba(100,200,100,0.9) !important;
      border-radius: 50% !important;
      transition: left 0.3s ease, background 0.4s !important;
      display: flex !important; align-items: center !important; justify-content: center !important;
      overflow: hidden !important;
    }
    #ygg-pcdb-root #ygg-toggle-btn.ygg-on #ygg-toggle-thumb {
      left: 26px !important; background: rgba(210,120,50,0.9) !important;
    }
    #ygg-pcdb-root #ygg-toggle-logo {
      width: 18px !important; height: 18px !important; object-fit: contain !important;
    }

    /* ─── CONSOMMATION ACTIVE ─── */
    #ygg-pcdb-root #ygg-active-cons {
      position: absolute !important;
      top: 12px !important; left: 50% !important; transform: translateX(-50%) !important;
      background: rgba(6,10,6,0.87) !important;
      backdrop-filter: blur(12px) !important; -webkit-backdrop-filter: blur(12px) !important;
      border: 1px solid rgba(100,160,80,0.2) !important;
      border-radius: 8px !important; padding: 6px 14px !important;
      display: none; /* contrôlé par JS */
      align-items: center !important; gap: 10px !important;
      font-size: 11px !important; color: #c8dfc0 !important;
      z-index: 20 !important; white-space: nowrap !important;
    }
    #ygg-pcdb-root #ygg-cons-icon { font-size: 16px !important; }
    #ygg-pcdb-root #ygg-cons-val {
      font-size: 16px !important; font-weight: 700 !important;
      font-family: 'Playfair Display', Georgia, serif !important;
      color: #9de090 !important; transition: color 0.5s !important;
    }
    #ygg-pcdb-root #ygg-cons-val.rich { color: #e07c4a !important; }
    #ygg-pcdb-root #ygg-cons-desc {
      font-size: 9px !important; color: rgba(150,195,130,0.5) !important;
    }

    /* ─── BOUTONS ACTION
         NOTE CRITIQUE : PAS de display !important ici.
         La visibilité est gérée par JS (inline style).
         Si on met display:flex !important, le JS ne peut plus cacher les boutons. ─── */
    #ygg-pcdb-root #ygg-actions {
      position: absolute !important;
      bottom: 20px !important; left: 50% !important; transform: translateX(-50%) !important;
      display: none; /* contrôlé par JS */
      gap: 8px !important; z-index: 20 !important;
      flex-wrap: wrap !important; justify-content: center !important;
      max-width: 90vw !important;
    }
    #ygg-pcdb-root .ygg-btn {
      background: rgba(8,14,8,0.84);
      backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
      border: 1px solid rgba(100,160,80,0.35);
      border-radius: 10px; padding: 11px 20px;
      color: #c8dfc0; font-family: 'Inter', sans-serif !important;
      font-size: 13px; font-weight: 500; cursor: pointer;
      /* display: flex sans !important → le JS peut le contrôler */
      display: flex; align-items: center; gap: 7px;
      white-space: nowrap;
      transition: background 0.22s, border-color 0.22s, transform 0.1s;
    }
    #ygg-pcdb-root .ygg-btn:hover {
      background: rgba(30,60,30,0.78);
      border-color: rgba(100,190,80,0.52);
    }
    #ygg-pcdb-root .ygg-btn:active { transform: scale(0.96); }

    /* ─── BOUTONS XR ─── */
    #ygg-pcdb-root #ygg-xr-btns {
      position: absolute !important; bottom: 20px !important; right: 12px !important;
      display: flex !important; gap: 8px !important; z-index: 20 !important;
    }
    #ygg-pcdb-root .ygg-xrbtn {
      background: rgba(8,16,26,0.84);
      backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
      border: 1px solid rgba(80,140,200,0.4);
      border-radius: 10px; padding: 11px 18px;
      color: #a0c8e8; font-family: 'Inter', sans-serif !important;
      font-size: 13px; font-weight: 500; cursor: pointer;
      transition: background 0.22s;
    }
    #ygg-pcdb-root .ygg-xrbtn:hover { background: rgba(20,40,80,0.78); }

    /* ─── MESSAGE ÉCO ─── */
    #ygg-pcdb-root #ygg-eco-msg {
      position: absolute !important;
      bottom: 140px !important; left: 50% !important; transform: translateX(-50%) !important;
      background: rgba(4,8,4,0.92) !important;
      backdrop-filter: blur(14px) !important; -webkit-backdrop-filter: blur(14px) !important;
      border: 1px solid rgba(100,160,80,0.2) !important;
      border-radius: 10px !important; padding: 14px 20px !important;
      max-width: 460px !important; width: calc(100vw - 24px) !important;
      text-align: center !important; color: #c8dfc0 !important;
      font-size: 12px !important; line-height: 1.65 !important;
      z-index: 20 !important;
      opacity: 0; pointer-events: none !important;
      transition: opacity 0.7s ease !important;
    }
    #ygg-pcdb-root #ygg-eco-msg.vis { opacity: 1 !important; }
    #ygg-pcdb-root .ygg-etitle {
      font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 14px !important; color: #9de090 !important;
      margin-bottom: 6px !important; display: block !important;
    }

    /* ─── JOURNAL ─── */
    #ygg-pcdb-root #ygg-journal {
      position: absolute !important;
      top: 100px !important; right: 12px !important;
      background: rgba(8,14,8,0.8) !important;
      backdrop-filter: blur(12px) !important; -webkit-backdrop-filter: blur(12px) !important;
      border: 1px solid rgba(100,160,80,0.18) !important;
      border-radius: 10px !important; padding: 10px !important;
      width: 210px !important; max-height: 275px !important; overflow-y: auto !important;
      display: none; z-index: 20 !important;
    }
    #ygg-pcdb-root #ygg-journal::-webkit-scrollbar { width: 4px !important; }
    #ygg-pcdb-root #ygg-journal::-webkit-scrollbar-thumb {
      background: rgba(100,160,80,0.3) !important; border-radius: 2px !important;
    }
    #ygg-pcdb-root .ygg-entry {
      font-size: 10px !important; color: rgba(165,205,150,0.65) !important;
      padding: 3px 0 !important; border-bottom: 1px solid rgba(100,160,80,0.1) !important;
      line-height: 1.44 !important;
    }
    #ygg-pcdb-root .ygg-entry:last-child { border-bottom: none !important; }
    #ygg-pcdb-root .ygg-etime { color: rgba(100,160,80,0.45) !important; }

    /* ─── BOUTON INFO ─── */
    #ygg-pcdb-root #ygg-info-btn {
      position: absolute !important; bottom: 20px !important; left: 12px !important;
      width: 42px !important; height: 42px !important;
      background: rgba(8,14,8,0.84) !important;
      backdrop-filter: blur(12px) !important; -webkit-backdrop-filter: blur(12px) !important;
      border: 1px solid rgba(100,160,80,0.35) !important; border-radius: 50% !important;
      color: #9de090 !important; font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 18px !important; font-style: italic !important; font-weight: 700 !important;
      cursor: pointer !important; z-index: 21 !important;
      display: flex !important; align-items: center !important; justify-content: center !important;
      transition: background 0.22s !important;
    }
    #ygg-pcdb-root #ygg-info-btn:hover { background: rgba(25,55,25,0.88) !important; }

    /* ─── PANNEAU AIDE ─── */
    #ygg-pcdb-root #ygg-help-panel {
      position: absolute !important; bottom: 72px !important; left: 12px !important;
      width: 295px !important; max-width: calc(100vw - 24px) !important;
      background: rgba(4,8,4,0.96) !important;
      backdrop-filter: blur(18px) !important; -webkit-backdrop-filter: blur(18px) !important;
      border: 1px solid rgba(100,160,80,0.26) !important;
      border-radius: 12px !important; padding: 16px !important;
      z-index: 22 !important; color: #c8dfc0 !important;
    }
    #ygg-pcdb-root #ygg-help-panel[hidden] { display: none !important; }
    #ygg-pcdb-root #ygg-help-close {
      position: absolute !important; top: 10px !important; right: 12px !important;
      background: none !important; border: none !important;
      color: rgba(150,195,130,0.5) !important;
      font-size: 20px !important; cursor: pointer !important; padding: 2px 6px !important;
    }
    #ygg-pcdb-root #ygg-help-close:hover { color: #9de090 !important; }
    #ygg-pcdb-root #ygg-help-panel h2 {
      font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 15px !important; color: #9de090 !important; margin-bottom: 10px !important;
    }
    #ygg-pcdb-root #ygg-help-panel h3 {
      font-size: 9px !important; text-transform: uppercase !important;
      letter-spacing: 1.2px !important; color: rgba(130,185,110,0.5) !important;
      margin: 8px 0 5px !important;
    }
    #ygg-pcdb-root #ygg-help-panel ul { list-style: none !important; }
    #ygg-pcdb-root #ygg-help-panel li {
      font-size: 11px !important; color: rgba(185,215,170,0.75) !important;
      padding: 2px 0 !important; line-height: 1.5 !important;
    }
    #ygg-pcdb-root .ygg-credit {
      margin-top: 10px !important; font-size: 9px !important;
      color: rgba(110,155,90,0.4) !important; text-align: center !important;
      padding-top: 8px !important; border-top: 1px solid rgba(100,160,80,0.1) !important;
    }

    /* ─── FLASH PINCH XR ─── */
    #ygg-pcdb-root #ygg-pinch-flash {
      position: absolute !important; inset: 0 !important;
      background: rgba(80,200,255,0.07) !important;
      z-index: 18 !important; pointer-events: none !important;
      opacity: 0 !important; transition: opacity 0.12s !important;
    }
    #ygg-pcdb-root #ygg-pinch-flash.fl { opacity: 1 !important; }

    /* ─── INTRO ─── */
    #ygg-pcdb-root #ygg-intro {
      position: absolute !important; inset: 0 !important;
      background: radial-gradient(ellipse at 50% 75%, #182a1a 0%, #050c05 70%) !important;
      z-index: 50 !important;
      display: flex !important; flex-direction: column !important;
      align-items: center !important; justify-content: center !important;
      text-align: center !important; padding: 30px !important;
      transition: opacity 1.1s ease !important;
    }
    #ygg-pcdb-root #ygg-intro.ygg-out {
      opacity: 0 !important; pointer-events: none !important;
    }
    #ygg-pcdb-root #ygg-intro h1 {
      font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 46px !important; color: #9de090 !important;
      letter-spacing: 3px !important; margin-bottom: 6px !important;
    }
    #ygg-pcdb-root .ygg-sub-intro {
      font-size: 13px !important; font-style: italic !important;
      color: rgba(165,205,150,0.5) !important; margin-bottom: 34px !important;
    }
    #ygg-pcdb-root #ygg-start-btn {
      background: rgba(35,72,35,0.45) !important;
      border: 1px solid rgba(100,190,80,0.45) !important;
      border-radius: 12px !important; padding: 16px 44px !important;
      color: #9de090 !important; font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 18px !important; cursor: pointer !important;
      transition: background 0.28s !important; margin-bottom: 14px !important;
    }
    #ygg-pcdb-root #ygg-start-btn:hover { background: rgba(45,90,45,0.58) !important; }
    #ygg-pcdb-root #ygg-reset-btn {
      font-size: 10px !important; color: rgba(110,155,90,0.36) !important;
      cursor: pointer !important; background: none !important; border: none !important;
      text-decoration: underline !important; text-underline-offset: 3px !important;
    }

    /* ─── MORAL ─── */
    #ygg-pcdb-root #ygg-moral {
      position: absolute !important; inset: 0 !important;
      background: rgba(2,4,2,0.96) !important;
      z-index: 60 !important;
      display: flex !important; flex-direction: column !important;
      align-items: center !important; justify-content: center !important;
      padding: 30px !important; text-align: center !important; overflow-y: auto !important;
    }
    #ygg-pcdb-root #ygg-moral[hidden] { display: none !important; }
    #ygg-pcdb-root #ygg-moral h2 {
      font-family: 'Playfair Display', Georgia, serif !important;
      font-size: 25px !important; color: #e6a8a8 !important; margin-bottom: 16px !important;
    }
    #ygg-pcdb-root #ygg-moral-text {
      font-size: 13px !important; color: rgba(215,195,185,0.75) !important;
      max-width: 500px !important; line-height: 1.8 !important; margin-bottom: 12px !important;
    }
    #ygg-pcdb-root .ygg-mstat {
      font-size: 17px !important; color: #7ec8e3 !important;
      font-weight: 600 !important; margin: 12px 0 !important; line-height: 1.7 !important;
    }
    #ygg-pcdb-root #ygg-moral-advice {
      font-size: 13px !important; color: rgba(215,195,185,0.65) !important;
      max-width: 500px !important; line-height: 1.8 !important; margin-bottom: 20px !important;
    }

    /* ─── ANIMATIONS ─── */
    @keyframes ygg-float {
      0%, 100% { transform: translateY(0); }
      50% { transform: translateY(-9px); }
    }
  </style>
</head>
<body>
<div id="ygg-pcdb-root">

  <canvas id="ygg-canvas"></canvas>

  <div id="ygg-ui">

    <!-- INTRO -->
    <div id="ygg-intro">
      <img decoding="async" id="ygg-intro-logo" src="https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1stroke_PCdlab_2026.svg" alt="Yggdrasil">
      <h1>Yggdrasil</h1>
      <p class="ygg-sub-intro">Plante un arbre. Nourris-le. Sauve la planète.</p>
      <button id="ygg-start-btn" type="button">Commencer</button>
      <button id="ygg-reset-btn" type="button">Nouvelle partie</button>
    </div>

    <!-- HUD -->
    <div id="ygg-hud">
      <div class="ygg-card" id="ygg-growth-card">
        <span class="ygg-lbl">🌿 Croissance</span>
        <span class="ygg-val" id="ygg-growth-val">0%</span>
        <span class="ygg-sub" id="ygg-stage-name">Graine</span>
      </div>
      <div id="ygg-logo-center">
        <img decoding="async" id="ygg-logo-img"
          src="https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1stroke_PCdlab_2026.svg"
          alt="YGGDRASIL" class="ygg-nb-logo">
      </div>
      <div class="ygg-card" id="ygg-water-card">
        <span class="ygg-lbl">💧 Eau utilisée</span>
        <span class="ygg-val blue" id="ygg-water-val">0 L</span>
        <span class="ygg-sub" id="ygg-water-eq">&nbsp;</span>
      </div>
    </div>

    <!-- CONSOMMATION ACTIVE -->
    <div id="ygg-active-cons">
      <span id="ygg-cons-icon">🪣</span>
      <span id="ygg-cons-val">5.2 mL/s</span>
      <span id="ygg-cons-desc">Mode Éco Actif : Empreinte Graphique Minimale</span>
    </div>

    <!-- TOGGLE -->
    <div id="ygg-toggle-bar">
      <div class="ygg-tside">
        <span class="ygg-tlabel">SOBRIÉTÉ ÉCO (N&amp;B)</span>
        <span class="ygg-cdisp eco"><span id="ygg-eco-v">5.2</span><span class="ygg-cunit"> mL/s</span></span>
      </div>
      <button id="ygg-toggle-btn" type="button" role="switch" aria-checked="false" aria-label="Mode affichage">
        <span id="ygg-toggle-thumb">
          <img decoding="async" id="ygg-toggle-logo"
            src="https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1_PCdlab_2026.svg"
            alt="" aria-hidden="true">
        </span>
      </button>
      <div class="ygg-tside">
        <span class="ygg-tlabel">RICHE COULEUR (DÉTAIL)</span>
        <span class="ygg-cdisp rich"><span id="ygg-rich-v">87.6</span><span class="ygg-cunit"> mL/s</span></span>
      </div>
    </div>

    <!-- JOURNAL -->
    <div id="ygg-journal" aria-live="polite"></div>

    <!-- ACTIONS — boutons cachés/montrés individuellement par JS -->
    <div id="ygg-actions">
      <button class="ygg-btn" id="ygg-btn-dig"   type="button">🤲 Creuser</button>
      <button class="ygg-btn" id="ygg-btn-plant" type="button" style="display:none">🌰 Planter</button>
      <button class="ygg-btn" id="ygg-btn-cover" type="button" style="display:none">🫳 Recouvrir</button>
      <button class="ygg-btn" id="ygg-btn-water" type="button" style="display:none">💧 Arroser</button>
      <button class="ygg-btn" id="ygg-btn-moral" type="button" style="display:none">📖 Réfléchir</button>
    </div>

    <!-- XR (injectés si disponibles) -->
    <div id="ygg-xr-btns"></div>

    <!-- ECO MSG -->
    <div id="ygg-eco-msg" role="status" aria-live="polite"></div>

    <!-- FLASH XR -->
    <div id="ygg-pinch-flash"></div>

    <!-- BOUTON INFO -->
    <button id="ygg-info-btn" type="button" aria-label="Aide et commandes" aria-expanded="false">i</button>

    <!-- PANNEAU AIDE -->
    <div id="ygg-help-panel" role="dialog" aria-label="Aide" hidden>
      <button id="ygg-help-close" type="button" aria-label="Fermer">×</button>
      <h2>🌳 YGGDRASIL — PCdlab 2026</h2>
      <h3>Souris / Clavier</h3>
      <ul>
        <li>🖱️ Glisser → Orbiter autour de l'arbre</li>
        <li>⚙️ Molette → Zoom avant / arrière</li>
        <li>Ctrl+Maj+R → Réinitialiser la partie</li>
      </ul>
      <h3>Tactile</h3>
      <ul>
        <li>👆 1 doigt glissé → Orbiter</li>
        <li>🤏 2 doigts pincés → Zoom</li>
      </ul>
      <h3>Quest 3 — Hand Tracking</h3>
      <ul>
        <li>✊ Pincer (index+pouce) → Arroser</li>
        <li>🤚 Mains visibles → Curseur goutte 3D</li>
        <li>AR → Placer l'arbre dans l'espace réel</li>
      </ul>
      <h3>Mode Affichage</h3>
      <ul>
        <li>🌑 Sobriété N&B = <strong>5.2 mL/s</strong></li>
        <li>🌈 Riche Couleur = <strong>87.6 mL/s</strong></li>
      </ul>
      <p class="ygg-credit">PCdlab 2026 · PrésentComposédesign<br>Code : Claude Sonnet × Anthropic</p>
    </div>

    <!-- MORAL -->
    <div id="ygg-moral" role="dialog" aria-modal="true" hidden>
      <h2>📖 La Vérité sur ton Arbre</h2>
      <p id="ygg-moral-text"></p>
      <div class="ygg-mstat" id="ygg-moral-stat"></div>
      <p id="ygg-moral-advice"></p>
      <button class="ygg-btn" id="ygg-close-moral" type="button">Je comprends 🌱</button>
    </div>

  </div><!-- #ygg-ui -->
</div><!-- #ygg-pcdb-root -->

<script type="module">
/* ══════════════════════════════════════════════════════════════════════
   YGGDRASIL — PCdlab 2026
   Three.js 0.161 · WebXR · Hand Tracking Quest 3
   Bug Fix : display !important removed from .ygg-btn
             → JS peut maintenant gérer la visibilité des boutons
   ══════════════════════════════════════════════════════════════════════ */

import * as THREE from 'https://unpkg.com/three@0.161.0/build/three.module.js';

/* ─── CONSTANTES ─── */
const SAVE_KEY    = 'ygg_pcdb_2026';
const WATER_PAGE  = 0.5;
const WATER_ARR   = 1.5;
const SHOWER_LPM  = 12;
const CONS_ECO    = 5.2;
const CONS_RICH   = 87.6;

const LOGO_GRADIENT = 'https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_gradient_PCdlab_2026.svg';
const LOGO_STROKE   = 'https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1stroke_PCdlab_2026.svg';
const LOGO_MAIN     = 'https://presentcomposedesign.fr/wp-content/uploads/2026/04/YGGDRASIL-LOGO_v1_PCdlab_2026.svg';

const GOLDEN_ANGLE = Math.PI * 2 * (1 - 2 / (1 + Math.sqrt(5)));
const FIB = [2, 3, 5, 8, 13, 21, 34];

const STAGES = [
  { name:'Graine',       min:0  },
  { name:'Germination',  min:5  },
  { name:'Jeune pousse', min:15 },
  { name:'Arbuste',      min:30 },
  { name:'Jeune arbre',  min:50 },
  { name:'Arbre mature', min:70 },
  { name:'Yggdrasil',   min:90 },
];

const ECO_FACTS = [
  "🚿 Une douche de 5 min = 60 litres.",
  "🥩 1 kg de bœuf = 15 400 litres d'eau.",
  "👕 Un t-shirt coton = 2 700 litres.",
  "🌾 L'agriculture utilise 70% de l'eau douce mondiale.",
  "💧 2,2 milliards sans accès à l'eau potable.",
  "🌍 La moitié du monde en stress hydrique d'ici 2025.",
  "☕ Une tasse de café = 140 litres produits.",
  "📱 Un smartphone = 12 000 litres fabriqué.",
  "🥑 Un avocat = 320 litres d'eau.",
  "🏠 Un Français consomme ~150 L/jour.",
];

/* ─── ÉTAT ─── */
function defaultState() {
  return {
    phase:'start', growth:0, totalWater:0,
    waterCount:0, pageLoads:0, pageWater:0,
    lastWaterTime:null, createdAt:Date.now(),
    journal:[], overwatered:false,
  };
}
function loadState() {
  try { const d = JSON.parse(localStorage.getItem(SAVE_KEY)); if (d?.phase) return d; } catch(e){}
  return defaultState();
}
let gs = loadState();
const save = () => localStorage.setItem(SAVE_KEY, JSON.stringify(gs));

gs.pageLoads = (gs.pageLoads||0) + 1;
gs.pageWater = (gs.pageWater||0) + WATER_PAGE;
save();

/* ─── TOGGLE STATE ─── */
let isColor = false;

/* ─── THREE.JS ─── */
const canvas = document.getElementById('ygg-canvas');

const renderer = new THREE.WebGLRenderer({ canvas, antialias:true, alpha:false });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.95;
renderer.xr.enabled = true;

const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x162617, 0.013);

const camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 0.1, 200);

/* worldGroup : tout l'environnement. Déplacé en XR pour positionner l'utilisateur */
const worldGroup = new THREE.Group();
scene.add(worldGroup);

/* ─── LUMIÈRES ─── */
scene.add(new THREE.AmbientLight(0x3a5a3a, 0.72));

const sun = new THREE.DirectionalLight(0xffe8c0, 1.28);
sun.position.set(8, 15, 5);
sun.castShadow = true;
sun.shadow.mapSize.set(2048, 2048);
sun.shadow.camera.near = 0.5; sun.shadow.camera.far = 60;
sun.shadow.camera.left = -18; sun.shadow.camera.right = 18;
sun.shadow.camera.top  = 18; sun.shadow.camera.bottom = -18;
sun.shadow.bias = -0.001; sun.shadow.normalBias = 0.02;
scene.add(sun);

const rim = new THREE.DirectionalLight(0x88aaff, 0.32);
rim.position.set(-5, 8, -5);
scene.add(rim);

/* ─── CIEL (dégradé shader) ─── */
const skyMat = new THREE.ShaderMaterial({
  side: THREE.BackSide,
  uniforms: {
    topColor:    { value: new THREE.Color(0x0a1628) },
    bottomColor: { value: new THREE.Color(0x2a4a2a) },
    offset:  { value: 20 }, exponent: { value: 0.5 },
  },
  vertexShader:`
    varying vec3 vWP;
    void main(){ vWP=(modelMatrix*vec4(position,1.0)).xyz; gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0); }`,
  fragmentShader:`
    uniform vec3 topColor,bottomColor; uniform float offset,exponent; varying vec3 vWP;
    void main(){float h=normalize(vWP+vec3(0,offset,0)).y; gl_FragColor=vec4(mix(bottomColor,topColor,max(pow(max(h,0.0),exponent),0.0)),1.0);}`,
});
worldGroup.add(new THREE.Mesh(new THREE.SphereGeometry(100,48,48), skyMat));

/* ─── SOL ─── */
const gnd = new THREE.Mesh(
  new THREE.PlaneGeometry(60,60,80,80),
  new THREE.MeshStandardMaterial({ color:0x2a5a1a, roughness:0.9 })
);
gnd.rotation.x = -Math.PI/2; gnd.receiveShadow = true;
worldGroup.add(gnd);

const soil = new THREE.Mesh(
  new THREE.CircleGeometry(1.5,48),
  new THREE.MeshStandardMaterial({ color:0x3a2a1a, roughness:1 })
);
soil.rotation.x = -Math.PI/2; soil.position.set(0,0.01,0); soil.receiveShadow = true;
worldGroup.add(soil);

/* ─── HERBE INSTANCIÉE ─── */
const GRASS_N = 10000;
const grassGeo = new THREE.PlaneGeometry(0.08, 0.5, 1, 3);
grassGeo.translate(0, 0.25, 0);

const grassMat = new THREE.ShaderMaterial({
  uniforms:{ time:{value:0}, wind:{value:0.3} },
  vertexShader:`
    uniform float time,wind;
    attribute float phase,ht;
    varying float vH;
    void main(){
      vH=position.y/0.5;
      vec3 p=position;
      p.x+=sin(time*2.0+phase)*wind*p.y*p.y + cos(time*1.3+phase*0.7)*wind*0.5*p.y;
      p.z+=cos(time*1.7+phase*1.3)*wind*0.3*p.y;
      p.x*=(1.0-vH*0.6); p.z*=(1.0-vH*0.6);
      gl_Position=projectionMatrix*modelViewMatrix*instanceMatrix*vec4(p*vec3(1,ht,1),1.0);
    }`,
  fragmentShader:`
    varying float vH;
    void main(){
      vec3 c=mix(vec3(0.14,0.34,0.09),vec3(0.3,0.6,0.14),vH);
      c=mix(c,vec3(0.38,0.68,0.18),vH*vH*0.5);
      gl_FragColor=vec4(c*mix(0.5,1.0,vH),1.0);
    }`,
  side:THREE.DoubleSide,
});

const grassMesh = new THREE.InstancedMesh(grassGeo, grassMat, GRASS_N);
const _pha = new Float32Array(GRASS_N);
const _ht  = new Float32Array(GRASS_N);
const _d   = new THREE.Object3D();
for(let i=0;i<GRASS_N;i++){
  const a=Math.random()*Math.PI*2, r=Math.random()*24+2;
  _d.position.set(Math.cos(a)*r, 0, Math.sin(a)*r);
  _d.rotation.set(0, Math.random()*Math.PI, 0);
  _d.scale.set(0.8+Math.random()*0.5, 1, 1);
  _d.updateMatrix();
  grassMesh.setMatrixAt(i, _d.matrix);
  _pha[i] = Math.random()*Math.PI*2;
  _ht[i]  = 0.6+Math.random()*0.8;
}
grassGeo.setAttribute('phase', new THREE.InstancedBufferAttribute(_pha,1));
grassGeo.setAttribute('ht',    new THREE.InstancedBufferAttribute(_ht,1));
grassMesh.instanceMatrix.needsUpdate = true;
worldGroup.add(grassMesh);

/* ─── FLEURS ─── */
const fCols = [0xff6b9d,0xffd93d,0xc084fc,0xffffff,0xff8fab];
for(let i=0;i<34;i++){
  const a=Math.random()*Math.PI*2, r=3+Math.random()*18;
  const fg = new THREE.Group();
  const stem = new THREE.Mesh(
    new THREE.CylinderGeometry(0.01,0.01,0.2,4),
    new THREE.MeshStandardMaterial({color:0x2e7d32})
  );
  stem.position.y=0.1; fg.add(stem);
  const petal = new THREE.Mesh(
    new THREE.SphereGeometry(0.05,6,6),
    new THREE.MeshStandardMaterial({color:fCols[i%fCols.length]})
  );
  petal.position.y=0.22; fg.add(petal);
  fg.position.set(Math.cos(a)*r, 0, Math.sin(a)*r);
  worldGroup.add(fg);
}

/* ─── CAILLOUX ─── */
for(let i=0;i<20;i++){
  const a=Math.random()*Math.PI*2, r=2+Math.random()*14;
  const pg = new THREE.SphereGeometry(0.05+Math.random()*0.08,6,6);
  pg.scale(1, 0.5, 1+Math.random()*0.3);
  const pm = new THREE.Mesh(pg, new THREE.MeshStandardMaterial({
    color: new THREE.Color().setHSL(0.08,0.1,0.3+Math.random()*0.2), roughness:0.95
  }));
  pm.position.set(Math.cos(a)*r, 0.02, Math.sin(a)*r);
  worldGroup.add(pm);
}

/* ─── GRAINE ─── */
const seedGeo = new THREE.SphereGeometry(0.12,16,16);
seedGeo.scale(1, 0.7, 0.8); // scale sur la géométrie (method correcte)
const seed = new THREE.Mesh(seedGeo, new THREE.MeshStandardMaterial({color:0x8B6914,roughness:0.8}));
seed.position.set(0, 0.5, 3);
seed.castShadow = true; seed.visible = false;
worldGroup.add(seed);

/* ─── TROU ─── */
const hole = new THREE.Mesh(
  new THREE.CylinderGeometry(0.4,0.3,0.3,32),
  new THREE.MeshStandardMaterial({color:0x1a0f05,roughness:1})
);
hole.position.set(0,-0.15,0); hole.visible = false;
worldGroup.add(hole);

/* ─── ARBRE ─── */
const treeGroup = new THREE.Group();
worldGroup.add(treeGroup);
let treeObjs = [];

/* ─── LUCIOLES ─── */
const ffN = 28;
const ffGeo = new THREE.BufferGeometry();
const ffPos = new Float32Array(ffN*3);
const ffPha = new Float32Array(ffN);
for(let i=0;i<ffN;i++){
  ffPos[i*3]=(Math.random()-.5)*18; ffPos[i*3+1]=0.5+Math.random()*4; ffPos[i*3+2]=(Math.random()-.5)*18;
  ffPha[i]=Math.random()*Math.PI*2;
}
ffGeo.setAttribute('position',new THREE.BufferAttribute(ffPos,3));
const ffMat = new THREE.PointsMaterial({color:0xffee88,size:0.1,transparent:true,opacity:0.55});
worldGroup.add(new THREE.Points(ffGeo,ffMat));
const fireflies = worldGroup.children[worldGroup.children.length-1];

/* ─── ARROSOIR ─── */
const canGroup = new THREE.Group();
canGroup.visible = false;
const canMat = new THREE.MeshStandardMaterial({color:0x4a7a8a,roughness:0.5,metalness:0.3});
const canBody = new THREE.Mesh(new THREE.CylinderGeometry(0.25,0.3,0.5,12), canMat);
canGroup.add(canBody);
const spout = new THREE.Mesh(new THREE.CylinderGeometry(0.04,0.06,0.4,8), canMat);
spout.position.set(0.2,0.15,0); spout.rotation.z=-0.8;
canGroup.add(spout);
canGroup.position.set(1.5,3,2); canGroup.rotation.z=-0.3;
worldGroup.add(canGroup);

/* ─── PARTICULES EAU ─── */
let waterP = null;
let waterA = {active:false,time:0};

(function initWater(){
  const n=200, geo=new THREE.BufferGeometry();
  const pos=new Float32Array(n*3), vel=new Float32Array(n*3);
  for(let i=0;i<n;i++){
    pos[i*3]=(Math.random()-.5)*1.5; pos[i*3+1]=3+Math.random()*2; pos[i*3+2]=(Math.random()-.5)*1.5;
    vel[i*3]=(Math.random()-.5)*.02; vel[i*3+1]=-.05-Math.random()*.08; vel[i*3+2]=(Math.random()-.5)*.02;
  }
  geo.setAttribute('position',new THREE.BufferAttribute(pos,3));
  geo.userData.velocity=vel;
  waterP = new THREE.Points(geo, new THREE.PointsMaterial({color:0x4dc8ff,size:.06,transparent:true,opacity:.7}));
  waterP.visible=false;
  worldGroup.add(waterP); // dans worldGroup pour coïncider avec l'arbre en XR
})();

function startWaterAnim(){
  waterA={active:true,time:0}; waterP.visible=true;
  const pos=waterP.geometry.attributes.position;
  for(let i=0;i<pos.count;i++) pos.setXYZ(i,(Math.random()-.5)*1.5,3+Math.random()*2,(Math.random()-.5)*1.5);
  pos.needsUpdate=true;
}

/* ─── RETICLE AR ─── */
const reticle = new THREE.Mesh(
  new THREE.RingGeometry(0.15,0.2,32).rotateX(-Math.PI/2),
  new THREE.MeshBasicMaterial({color:0x00ffbf})
);
reticle.matrixAutoUpdate=false; reticle.visible=false;
scene.add(reticle);

/* ─── HAND TRACKING QUEST 3 ─── */
const XR_JOINTS = [
  'wrist',
  'thumb-metacarpal','thumb-phalanx-proximal','thumb-phalanx-distal','thumb-tip',
  'index-finger-metacarpal','index-finger-phalanx-proximal','index-finger-phalanx-intermediate','index-finger-phalanx-distal','index-finger-tip',
  'middle-finger-metacarpal','middle-finger-phalanx-proximal','middle-finger-phalanx-intermediate','middle-finger-phalanx-distal','middle-finger-tip',
  'ring-finger-metacarpal','ring-finger-phalanx-proximal','ring-finger-phalanx-intermediate','ring-finger-phalanx-distal','ring-finger-tip',
  'pinky-finger-metacarpal','pinky-finger-phalanx-proximal','pinky-finger-phalanx-intermediate','pinky-finger-phalanx-distal','pinky-finger-tip',
];

const jGeo = new THREE.SphereGeometry(0.007,6,6);
const jMat = new THREE.MeshStandardMaterial({color:0xe8c8a0,roughness:0.6});
const handMaps = [{},{}]; // joint name → Mesh, per hand
for(let h=0;h<2;h++){
  for(const name of XR_JOINTS){
    const m=new THREE.Mesh(jGeo,jMat);
    m.visible=false; scene.add(m);
    handMaps[h][name]=m;
  }
}
const dropCursor = new THREE.Mesh(
  new THREE.SphereGeometry(0.022,8,8),
  new THREE.MeshStandardMaterial({color:0x4dc8ff,transparent:true,opacity:0.82})
);
dropCursor.visible=false; scene.add(dropCursor);

const xrHand0 = renderer.xr.getHand(0);
const xrHand1 = renderer.xr.getHand(1);
scene.add(xrHand0); scene.add(xrHand1);

// AR controller pour placement
const arCtrl = renderer.xr.getController(0);
arCtrl.addEventListener('select',()=>{
  if(reticle.visible){ treeGroup.position.setFromMatrixPosition(reticle.matrix); treeGroup.updateMatrixWorld(true); }
});
scene.add(arCtrl);

let pinchWas0=false, pinchWas1=false, lastPinch=0;

function pinchDist(hand){
  const a=hand.joints?.['index-finger-tip'], b=hand.joints?.['thumb-tip'];
  return (a&&b&&a.jointRadius!==undefined&&b.jointRadius!==undefined)
    ? a.position.distanceTo(b.position) : Infinity;
}
function updateHandViz(hand, map, isRight){
  if(!hand.joints){ Object.values(map).forEach(m=>m.visible=false); if(isRight)dropCursor.visible=false; return; }
  for(const [n,m] of Object.entries(map)){
    const j=hand.joints[n];
    if(j&&j.jointRadius!==undefined){ m.visible=true; m.position.copy(j.position); m.quaternion.copy(j.quaternion); }
    else { m.visible=false; }
  }
  if(isRight){
    const tip=hand.joints['index-finger-tip'];
    if(tip&&tip.jointRadius!==undefined){
      dropCursor.visible=true; dropCursor.position.copy(tip.position); dropCursor.position.y-=0.03;
    } else { dropCursor.visible=false; }
  }
}

/* ─── XR BOUTONS CUSTOM ─── */
let xrSession=null;
async function initXR(){
  if(!navigator.xr) return;
  const c=document.getElementById('ygg-xr-btns');
  try{ if(await navigator.xr.isSessionSupported('immersive-vr')){ const b=mkXRBtn('🥽 VR',()=>enterXR('immersive-vr')); c.appendChild(b); } }catch(e){}
  try{ if(await navigator.xr.isSessionSupported('immersive-ar')){ const b=mkXRBtn('📷 AR',()=>enterXR('immersive-ar')); c.appendChild(b); } }catch(e){}
}
function mkXRBtn(label,fn){
  const b=document.createElement('button');
  b.className='ygg-xrbtn'; b.textContent=label; b.addEventListener('click',fn); return b;
}
async function enterXR(mode){
  if(xrSession){ try{await xrSession.end();}catch(e){} return; }
  const opts={
    requiredFeatures:['local-floor'],
    optionalFeatures:['hand-tracking', mode==='immersive-ar'?'hit-test':'bounded-floor'],
  };
  if(mode==='immersive-ar'){
    opts.optionalFeatures.push('dom-overlay');
    opts.domOverlay={root:document.getElementById('ygg-ui')};
  }
  try{
    const s=await navigator.xr.requestSession(mode,opts);
    xrSession=s; renderer.xr.setSession(s);
    s.addEventListener('end',()=>{ xrSession=null; worldGroup.position.set(0,0,0); updateCam(); });
    // Décale l'utilisateur à 5m de l'arbre (évite de spawner dans le tronc)
    try{
      const rs=await s.requestReferenceSpace('local-floor');
      const off=new XRRigidTransform({x:0,y:0,z:-5,w:1});
      renderer.xr.setReferenceSpace(rs.getOffsetReferenceSpace(off));
    }catch(e){ worldGroup.position.z=-5; }
  }catch(err){ console.warn('XR failed:',err); }
}

let hitSrc=null, hitSrcReq=false;

/* ─── CAMÉRA ORBITE (desktop/mobile) ─── */
let drag=false, pmx=0, pmy=0, azimuth=0, polar=0.5, camR=12;
function updateCam(){
  if(renderer.xr.isPresenting) return;
  camera.position.set(camR*Math.sin(polar)*Math.cos(azimuth), camR*Math.cos(polar), camR*Math.sin(polar)*Math.sin(azimuth));
  camera.lookAt(0,2,0);
}
updateCam();

/* ─── LOGIQUE JEU ─── */
const getStage = g => { let s=STAGES[0]; for(const st of STAGES) if(g>=st.min) s=st; return s; };
const fmtW = l => l<1?`${(l*1000).toFixed(0)} mL`:`${l.toFixed(1)} L`;
const wEq  = l => { const s=(l/SHOWER_LPM)*60; return s<60?`≈ ${s.toFixed(0)}s de douche`:`≈ ${(s/60).toFixed(1)}min de douche`; };
const rEco = () => ECO_FACTS[Math.floor(Math.random()*ECO_FACTS.length)];

function addJournal(txt){
  const d=new Date(), t=`${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
  gs.journal.unshift({time:t,text:txt});
  if(gs.journal.length>50) gs.journal.pop();
  save(); renderJournal();
}
function renderJournal(){
  document.getElementById('ygg-journal').innerHTML =
    gs.journal.map(e=>`<div class="ygg-entry"><span class="ygg-etime">${e.time}</span> ${e.text}</div>`).join('');
}

function showEco(title,text,dur=6000){
  const el=document.getElementById('ygg-eco-msg');
  el.innerHTML=`<span class="ygg-etitle">${title}</span>${text}`;
  el.classList.add('vis');
  clearTimeout(el._t); el._t=setTimeout(()=>el.classList.remove('vis'),dur);
}

function updateUI(){
  const st=getStage(gs.growth);
  document.getElementById('ygg-growth-val').textContent = `${Math.floor(gs.growth)}%`;
  document.getElementById('ygg-stage-name').textContent = st.name;
  document.getElementById('ygg-water-val').textContent  = fmtW(gs.totalWater);
  document.getElementById('ygg-water-eq').textContent   = wEq(gs.totalWater);
  if(gs.lastWaterTime){
    const mn=Math.floor((Date.now()-gs.lastWaterTime)/60000);
    const hr=Math.floor(mn/60), dy=Math.floor(hr/24);
    const ts=mn<1?"à l'instant":dy>0?`il y a ${dy}j`:hr>0?`il y a ${hr}h`:`il y a ${mn}min`;
    document.getElementById('ygg-water-eq').textContent=ts;
  }
}

/* ─── MODE AFFICHAGE ─── */
function setDisplayMode(color){
  isColor=color;
  const btn=document.getElementById('ygg-toggle-btn');
  btn.setAttribute('aria-checked', color?'true':'false');
  btn.classList.toggle('ygg-on', color);

  const logoImg  = document.getElementById('ygg-logo-img');
  const introLgo = document.getElementById('ygg-intro-logo');
  const togLgo   = document.getElementById('ygg-toggle-logo');

  if(color){
    canvas.classList.remove('ygg-nb');
    renderer.toneMappingExposure=1.1;
    skyMat.uniforms.topColor.value.set(0x0a1628);
    skyMat.uniforms.bottomColor.value.set(0x2a4a2a);
    logoImg.src=LOGO_GRADIENT; logoImg.classList.remove('ygg-nb-logo');
    introLgo.src=LOGO_GRADIENT; introLgo.classList.add('ygg-color-logo');
    togLgo.src=LOGO_GRADIENT;
    const cv=document.getElementById('ygg-cons-val');
    cv.classList.add('rich');
    animateCons(cv,CONS_RICH);
    document.getElementById('ygg-cons-desc').textContent='Mode Riche Actif : Empreinte Graphique Maximale';
    document.getElementById('ygg-cons-icon').textContent='💻';
  } else {
    canvas.classList.add('ygg-nb');
    renderer.toneMappingExposure=0.75;
    skyMat.uniforms.topColor.value.set(0x0d1520);
    skyMat.uniforms.bottomColor.value.set(0x1e2a1e);
    logoImg.src=LOGO_STROKE; logoImg.classList.add('ygg-nb-logo');
    introLgo.src=LOGO_STROKE; introLgo.classList.remove('ygg-color-logo');
    togLgo.src=LOGO_MAIN;
    const cv=document.getElementById('ygg-cons-val');
    cv.classList.remove('rich');
    animateCons(cv,CONS_ECO);
    document.getElementById('ygg-cons-desc').textContent='Mode Éco Actif : Empreinte Graphique Minimale';
    document.getElementById('ygg-cons-icon').textContent='🪣';
  }
}

function animateCons(el,target){
  const from=parseFloat(el.textContent)||0, t0=performance.now();
  (function step(now){
    const p=Math.min((now-t0)/800,1), e=p<.5?2*p*p:-1+(4-2*p)*p;
    el.textContent=(from+(target-from)*e).toFixed(1)+' mL/s';
    if(p<1) requestAnimationFrame(step);
  })(t0);
}

/* ─── CONSTRUCTION ARBRE ─── */
function buildTree(growth){
  treeObjs.forEach(o=>{
    treeGroup.remove(o);
    o.geometry?.dispose();
    (Array.isArray(o.material)?o.material:[o.material]).forEach(m=>m?.dispose());
  });
  treeObjs=[];
  if(growth<=0) return;
  const t=growth/100, trunkH=0.3+t*8, trunkR=0.05+t*0.6;
  const trunkCol=growth>=90?0x4a3a2a:0x3a2a1a;

  const tGeo=new THREE.CylinderGeometry(trunkR*.6,trunkR,trunkH,20,12);
  const tp=tGeo.attributes.position;
  for(let i=0;i<tp.count;i++) tp.setX(i,tp.getX(i)+Math.sin(tp.getY(i)/trunkH*2)*t*.3);
  tGeo.computeVertexNormals();
  const trunk=new THREE.Mesh(tGeo,new THREE.MeshStandardMaterial({color:trunkCol,roughness:.9}));
  trunk.position.y=trunkH/2; trunk.castShadow=true;
  treeGroup.add(trunk); treeObjs.push(trunk);

  if(growth>30){
    let fi=Math.max(0,Math.floor((growth-30)/10)); if(fi>=FIB.length) fi=FIB.length-1;
    for(let i=0;i<FIB[fi];i++){
      const ang=i*GOLDEN_ANGLE+Math.random()*.2;
      const bH=.5+t*3*(.5+Math.random()*.5), bR=.02+t*.15, bY=trunkH*(.4+(i/FIB[fi])*.5);
      const b=new THREE.Mesh(new THREE.CylinderGeometry(bR*.3,bR,bH,10),
        new THREE.MeshStandardMaterial({color:trunkCol,roughness:.9}));
      b.position.set(Math.cos(ang)*trunkR*.8,bY,Math.sin(ang)*trunkR*.8);
      b.rotation.z=(Math.cos(ang)>0?-1:1)*(.4+Math.random()*.6); b.rotation.y=ang;
      b.castShadow=true; treeGroup.add(b); treeObjs.push(b);
    }
  }

  if(growth>10){
    const layers=growth>=90?5:(growth>=50?3:1);
    const leafCol=growth>=90?0xd4af37:(growth>=70?0x1a6b1a:0x2e8b2e);
    for(let l=0;l<layers;l++){
      const cR=(.3+t*3.5)*(1-l*.15), cY=trunkH*.7+l*trunkH*.15;
      const cGeo=new THREE.SphereGeometry(cR,26,16);
      const cp=cGeo.attributes.position;
      for(let i=0;i<cp.count;i++){const n=.82+Math.random()*.36; cp.setXYZ(i,cp.getX(i)*n,cp.getY(i)*n,cp.getZ(i)*n);}
      cGeo.computeVertexNormals();
      const c=new THREE.Mesh(cGeo,new THREE.MeshStandardMaterial({color:leafCol,roughness:.8,metalness:growth>=90?.2:0}));
      c.name=`canopy_${l}`; c.position.set(Math.sin(l*GOLDEN_ANGLE)*.3,cY,Math.cos(l*GOLDEN_ANGLE)*.3);
      c.castShadow=true; treeGroup.add(c); treeObjs.push(c);
    }
    if(growth>=90){
      for(let i=0;i<8;i++){
        const ra=(i/8)*Math.PI*2, rl=2+Math.random()*2;
        const r=new THREE.Mesh(new THREE.CylinderGeometry(.05,.2,rl,10),
          new THREE.MeshStandardMaterial({color:0x3a2a1a,roughness:1}));
        r.position.set(Math.cos(ra)*rl*.4,.1,Math.sin(ra)*rl*.4); r.rotation.z=Math.cos(ra)*1.2; r.rotation.y=ra;
        treeGroup.add(r); treeObjs.push(r);
      }
      const gGeo=new THREE.BufferGeometry();
      const gp=new Float32Array(50*3);
      for(let i=0;i<50;i++){gp[i*3]=(Math.random()-.5)*6;gp[i*3+1]=2+Math.random()*(trunkH*.8);gp[i*3+2]=(Math.random()-.5)*6;}
      gGeo.setAttribute('position',new THREE.BufferAttribute(gp,3));
      const gpts=new THREE.Points(gGeo,new THREE.PointsMaterial({color:0xffd700,size:.15,transparent:true,opacity:.6}));
      gpts.name='yggGlow'; treeGroup.add(gpts); treeObjs.push(gpts);
    }
  }
}

/* ─── ARROSAGE ─── */
function doWatering(){
  const now=Date.now(), mins=gs.lastWaterTime?(now-gs.lastWaterTime)/60000:Infinity;
  const used=WATER_ARR+gs.pageWater;
  gs.totalWater+=used; gs.pageWater=0; gs.waterCount++; gs.lastWaterTime=now;

  let gain=0;
  if(gs.phase==='firstWater'){
    gain=5; addJournal(`💧 Premier arrosage ! ${fmtW(used)}.`);
  } else if(mins<1){
    gain=.5; gs.overwatered=true;
    addJournal(`⚠️ Trop fréquent. ${fmtW(used)} gaspillés.`);
    showEco('⚠️ Trop d\'eau !',`${fmtW(used)} utilisés — l'arbre n'en avait pas besoin.<br>${rEco()}`);
  } else if(mins<5){
    gain=2; addJournal(`💧 Arrosage. ${fmtW(used)}.`);
    showEco('💧 Arrosage',`${fmtW(used)} (${wEq(used)}). ${rEco()}`);
  } else if(mins<60){
    gain=5; addJournal(`💧 Bon arrosage ! ${fmtW(used)}.`);
    showEco('🌿 Bon timing !',`L'arbre apprécie un arrosage espacé. ${fmtW(used)}. ${rEco()}`);
  } else {
    gain=10+Math.min(mins/120,10);
    addJournal(`🌟 Arrosage patient ! ${fmtW(used)}.`);
    showEco('🌟 Vertueux !',`Ta patience est récompensée ! Croissance bonus. ${rEco()}`);
  }

  gs.growth=Math.min(100,gs.growth+gain);
  startWaterAnim();
  canGroup.visible=true;
  setTimeout(()=>{canGroup.visible=false;},3000);
  buildTree(gs.growth);

  if(gs.phase==='firstWater'){
    setPhase('growing');
    showEco('🌱 Germination !',`Ta graine germe ! ${fmtW(used)} utilisés (dont ${fmtW(WATER_PAGE)} à l'ouverture). ${rEco()}`);
  }
  if(gs.growth>=90&&gs.phase!=='yggdrasil'){
    setPhase('yggdrasil');
    addJournal('🌳✨ Ton arbre est devenu YGGDRASIL !');
    showEco('✨ YGGDRASIL ✨',`Forme ultime ! ${fmtW(gs.totalWater)} utilisés. Clique 📖 pour réfléchir.`,9000);
  }
  save(); updateUI();
  // Flash pinch XR
  const fl=document.getElementById('ygg-pinch-flash');
  fl.classList.add('fl'); setTimeout(()=>fl.classList.remove('fl'),180);
}

/* ─── PHASES ─── */
let digA={active:false,time:0}, plantA={active:false,time:0}, coverA={active:false,time:0};

/* Utilitaire : montre/cache les boutons sans conflit !important */
function showBtns(...ids){ ['dig','plant','cover','water','moral'].forEach(id=>{ const b=document.getElementById(`ygg-btn-${id}`); if(b) b.style.display=ids.includes(id)?'flex':'none'; }); }

function setPhase(phase){
  gs.phase=phase; save();
  const showHUD=!['start','digging','planting','covering'].includes(phase);
  document.getElementById('ygg-hud').style.display       = showHUD?'flex':'none';
  document.getElementById('ygg-active-cons').style.display = showHUD?'flex':'none';
  document.getElementById('ygg-journal').style.display    = showHUD?'block':'none';
  if(showHUD) renderJournal();

  switch(phase){
    case 'start':
      seed.visible=true; seed.position.set(0,.5,3); seed.scale.setScalar(1);
      showBtns('dig'); break;
    case 'digging':
      showBtns(); digA={active:true,time:0}; break;
    case 'planting':
      seed.visible=true; seed.position.set(0,.5,3); seed.scale.setScalar(1);
      showBtns('plant'); break;
    case 'covering':
      showBtns('cover'); break;
    case 'firstWater':
      showBtns('water'); break;
    case 'growing':
    case 'yggdrasil':
      showBtns('water','moral');
      buildTree(gs.growth); break;
  }
  updateUI();
}

function showMoral(){
  document.getElementById('ygg-moral').hidden=false;
  const tw=gs.totalWater, pw=gs.pageLoads*WATER_PAGE;
  document.getElementById('ygg-moral-text').innerHTML=`
    Ton arbre est magnifique. Chaque visite consomme <strong>${fmtW(WATER_PAGE)}</strong> symboliquement,
    et chaque arrosage <strong>${fmtW(WATER_ARR)}</strong> de plus.<br><br>
    <em>Les datacenters d'Internet consomment des milliards de litres pour leur refroidissement. Chaque pixel compte.</em>`;
  document.getElementById('ygg-moral-stat').innerHTML=
    `💧 Total : ${fmtW(tw)}<br>🌱 Dont ${fmtW(pw)} en ouvrant la page ${gs.pageLoads}×<br>🚿 ${wEq(tw)}`;
  document.getElementById('ygg-moral-advice').innerHTML=
    `<strong>La morale :</strong> Le meilleur joueur n'est pas celui qui a le plus gros arbre —
     c'est celui qui a utilisé le <em>moins d'eau</em> pour y arriver.<br><br>
     <strong style="color:#9de090;">Score écologique : ${Math.max(0,100-Math.floor(tw*2))}/100</strong>`;
}

/* ─── DÉMARRAGE DU JEU ─── */
function startGame(){
  const intro=document.getElementById('ygg-intro');
  intro.classList.add('ygg-out');
  setTimeout(()=>{ intro.style.display='none'; },1200);

  document.getElementById('ygg-actions').style.display='flex';
  document.getElementById('ygg-toggle-bar').style.display='flex';

  setDisplayMode(false); // N&B par défaut

  setPhase(gs.phase);

  if(gs.phase==='start'){
    showEco('🌰 Ta graine','Tu as une graine. Creuse un trou dans le sol pour la planter.');
  }
  if(['growing','yggdrasil'].includes(gs.phase)){
    setTimeout(()=>showEco('🌱 Connexion détectée',
      `Rien qu'en ouvrant cette page, <strong>${fmtW(WATER_PAGE)}</strong> dépensés. ${rEco()}`), 1500);
  }
}

/* ─── EVENT LISTENERS ─── */
document.getElementById('ygg-start-btn').addEventListener('click', startGame);

document.getElementById('ygg-reset-btn').addEventListener('click',()=>{
  localStorage.removeItem(SAVE_KEY); location.reload();
});

document.getElementById('ygg-toggle-btn').addEventListener('click',()=> setDisplayMode(!isColor));

document.getElementById('ygg-btn-dig').addEventListener('click',()=>{
  setPhase('digging'); addJournal('🤲 Tu creuses un trou dans la terre...');
});
document.getElementById('ygg-btn-plant').addEventListener('click',()=>{
  setPhase('covering'); plantA={active:true,time:0};
  addJournal('🌰 Tu déposes la graine au creux de la terre.');
});
document.getElementById('ygg-btn-cover').addEventListener('click',()=>{
  coverA={active:true,time:0};
  addJournal('🫳 Tu recouvres doucement la graine de terre.');
  setTimeout(()=>{
    setPhase('firstWater');
    showEco('🌱 Première étape','Ta graine est plantée. Elle a besoin de son premier arrosage pour germer.');
  },1800);
});
document.getElementById('ygg-btn-water').addEventListener('click', doWatering);
document.getElementById('ygg-btn-moral').addEventListener('click', showMoral);
document.getElementById('ygg-close-moral').addEventListener('click',()=>{ document.getElementById('ygg-moral').hidden=true; });

// Bouton i
const infoBtn=document.getElementById('ygg-info-btn');
const helpPanel=document.getElementById('ygg-help-panel');
infoBtn.addEventListener('click',()=>{
  const h=helpPanel.hidden; helpPanel.hidden=!h; infoBtn.setAttribute('aria-expanded',h?'true':'false');
});
document.getElementById('ygg-help-close').addEventListener('click',()=>{ helpPanel.hidden=true; infoBtn.setAttribute('aria-expanded','false'); });

// Orbite souris
canvas.addEventListener('pointerdown',e=>{drag=true;pmx=e.clientX;pmy=e.clientY;});
canvas.addEventListener('pointerup',()=>drag=false);
canvas.addEventListener('pointerleave',()=>drag=false);
canvas.addEventListener('pointermove',e=>{
  if(!drag) return;
  azimuth-=(e.clientX-pmx)*.005; polar=Math.max(.08,Math.min(Math.PI/2-.05,polar-(e.clientY-pmy)*.005));
  pmx=e.clientX; pmy=e.clientY; updateCam();
});

// Zoom molette
window.addEventListener('wheel',e=>{
  e.preventDefault(); camR=Math.max(4,Math.min(28,camR+e.deltaY*.01)); updateCam();
},{passive:false});

// Zoom tactile
let ltd=0;
canvas.addEventListener('touchstart',e=>{ if(e.touches.length===2) ltd=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY); });
canvas.addEventListener('touchmove',e=>{
  if(e.touches.length===2){
    e.preventDefault();
    const d=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY);
    camR=Math.max(4,Math.min(28,camR-(d-ltd)*.05)); ltd=d; updateCam();
  }
},{passive:false});

// Reset keyboard
window.addEventListener('keydown',e=>{ if(e.key==='r'&&e.ctrlKey&&e.shiftKey){localStorage.removeItem(SAVE_KEY);location.reload();} });

// Resize
window.addEventListener('resize',()=>{
  camera.aspect=window.innerWidth/window.innerHeight; camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth,window.innerHeight); updateCam();
});

/* ─── INIT ─── */
if(gs.phase!=='start') document.getElementById('ygg-start-btn').textContent='Retrouver mon arbre';
// Logo intro N&B par défaut (fond sombre → inversion)
document.getElementById('ygg-intro-logo').src=LOGO_STROKE;
document.getElementById('ygg-logo-img').src=LOGO_STROKE;
canvas.classList.add('ygg-nb');
initXR();

/* ─── BOUCLE ANIMATION ─── */
const clock=new THREE.Clock();

renderer.setAnimationLoop((timestamp, frame)=>{
  const dt=clock.getDelta(), t=clock.elapsedTime;

  /* Herbe */
  grassMat.uniforms.time.value=t;

  /* Lucioles */
  const fp=ffGeo.attributes.position;
  for(let i=0;i<ffN;i++){
    fp.setY(i,fp.getY(i)+Math.sin(t*.5+ffPha[i])*.002);
    fp.setX(i,fp.getX(i)+Math.cos(t*.3+ffPha[i])*.001);
  }
  fp.needsUpdate=true;
  ffMat.opacity=.3+Math.sin(t*2)*.24;

  /* Graine flottante */
  if(seed.visible&&gs.phase==='start'){
    seed.position.y=.5+Math.sin(t*2)*.05; seed.rotation.y=t*.5;
  }

  /* Phase : creuser */
  if(digA.active){
    digA.time+=dt*1.2; const p=Math.min(digA.time,1);
    if(p>=1){ digA.active=false; hole.visible=true; setPhase('planting'); showEco('🕳️ Trou creusé','Le sol est prêt. Plante ta graine !'); }
  }

  /* Phase : planter */
  if(plantA.active){
    plantA.time+=dt*1.2; const p=Math.min(plantA.time,1);
    seed.position.set(0,.5-p*.6,3-p*3); seed.scale.setScalar(1-p*.3);
    if(p>=1){ plantA.active=false; seed.visible=false; }
  }

  /* Phase : recouvrir */
  if(coverA.active){
    coverA.time+=dt*.9; const p=Math.min(coverA.time,1);
    hole.scale.y=1-p;
    if(p>=1){ coverA.active=false; hole.visible=false; hole.scale.y=1; }
  }

  /* Eau */
  if(waterA.active){
    waterA.time+=dt;
    const pos=waterP.geometry.attributes.position, vel=waterP.geometry.userData.velocity;
    for(let i=0;i<pos.count;i++){
      pos.setX(i,pos.getX(i)+vel[i*3]); pos.setY(i,pos.getY(i)+vel[i*3+1]); pos.setZ(i,pos.getZ(i)+vel[i*3+2]);
      vel[i*3+1]-=.001;
      if(pos.getY(i)<0){ pos.setXYZ(i,(Math.random()-.5)*1.5,3+Math.random(),(Math.random()-.5)*1.5); vel[i*3+1]=-.05-Math.random()*.08; }
    }
    pos.needsUpdate=true;
    if(waterA.time>3){ waterA.active=false; waterP.visible=false; }
  }

  /* Arrosoir */
  if(canGroup.visible){ canGroup.position.y=3+Math.sin(t*3)*.1; canGroup.rotation.z=-.3-Math.sin(t*2)*.1; }

  /* Canopées ondulantes */
  treeGroup.rotation.y=Math.sin(t*.28)*.018;
  treeObjs.forEach(o=>{ if(o.name?.startsWith('canopy')) o.position.x+=Math.sin(t*.8+o.id)*.0007; });
  const glow=treeGroup.getObjectByName('yggGlow');
  if(glow){ glow.rotation.y=t*.1; glow.material.opacity=.3+Math.sin(t)*.3; }

  /* ─── HAND TRACKING XR ─── */
  if(renderer.xr.isPresenting){
    updateHandViz(xrHand0,handMaps[0],false);
    updateHandViz(xrHand1,handMaps[1],true);

    const d0=pinchDist(xrHand0), isPinch0=d0<.03;
    if(isPinch0&&!pinchWas0){
      const now=Date.now();
      if(now-lastPinch>2000&&['firstWater','growing','yggdrasil'].includes(gs.phase)){ lastPinch=now; doWatering(); }
    }
    pinchWas0=isPinch0;

    const d1=pinchDist(xrHand1), isPinch1=d1<.03;
    if(isPinch1&&!pinchWas1){
      const now=Date.now();
      if(now-lastPinch>2000&&['firstWater','growing','yggdrasil'].includes(gs.phase)){ lastPinch=now; doWatering(); }
    }
    pinchWas1=isPinch1;

    if(dropCursor){
      dropCursor.material.opacity=(isPinch0||isPinch1)?1:.8;
      dropCursor.scale.setScalar((isPinch0||isPinch1)?1.4:1);
    }

    /* AR Hit Test */
    if(frame){
      const refSpace=renderer.xr.getReferenceSpace(), sess=renderer.xr.getSession();
      if(!hitSrcReq&&sess){
        sess.requestReferenceSpace('viewer').then(vs=>
          sess.requestHitTestSource({space:vs}).then(s=>{ hitSrc=s; })
        );
        sess.addEventListener('end',()=>{ hitSrcReq=false; hitSrc=null; reticle.visible=false; });
        hitSrcReq=true;
      }
      if(hitSrc){
        const res=frame.getHitTestResults(hitSrc);
        if(res.length>0){ reticle.visible=true; reticle.matrix.fromArray(res[0].getPose(refSpace).transform.matrix); }
        else { reticle.visible=false; }
      }
    }
  } else {
    handMaps.forEach(m=>Object.values(m).forEach(mesh=>mesh.visible=false));
    if(dropCursor) dropCursor.visible=false;
    updateCam();
  }

  renderer.render(scene,camera);
});
</script>
</body>
</html>
				</div>
				</div>
				</div>
		<div class="elementor-element elementor-element-cb9e7c6 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="cb9e7c6" data-element_type="container" data-e-type="container">
					<div class="e-con-inner">
					</div>
				</div>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/36446-2/">//*</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>spz</title>
		<link>https://presentcomposedesign.fr/spz/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 10 Apr 2026 08:18:05 +0000</pubDate>
				<category><![CDATA[Design produit]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=36271</guid>

					<description><![CDATA[<p>Initialisation Ouvrir en AR / VR Position &#38; Echelle X0.00 Y0.00 Z0.00 Echelle Reglages Ambiant0.70 Lumiere0.90 Opacite1.00 Brillance0.40 Reflexion0.20 Medias Video Plat 360 Sphere Cylindrique Cubique Taille3.0 Charger video Retirer video Image Plat 360 Sphere Cylindrique Cubique Taille3.0 Charger image Retirer image Audio Volume0.80 Charger audio Triggers XR GPS &#8212;, &#8212; Rayon m50 Activer GPS + Zone ici Image Tracker Largeur m0.20 Ajouter tracker &#160;Anim Aucune Tourniquet Flottement Respiration Expansion Suivre souris Orbite douce Scroll Zoom pulse Apparition GlisserRotation ScrollZoom Shift+dragPan Dbl-clicReset</p>
<p>Cet article <a href="https://presentcomposedesign.fr/spz/">spz</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="36271" class="elementor elementor-36271">
				<div class="elementor-element elementor-element-a43c5a5 e-con-full e-flex wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="a43c5a5" data-element_type="container" data-e-type="container">
				<div class="elementor-element elementor-element-888a871 elementor-widget__width-inherit elementor-widget elementor-widget-html" data-id="888a871" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!--
╔═══════════════════════════════════════════════════════════════╗
║ XR Viewer Ultimate V2, © All rights reserved.                 ║
║---------------------------------------------------------------║
║ Dev-Xprmnts · VR_Xprmnts, Present Compound Design             ║
║ Alban DESBARAX - Designer 360° //* Creative Technologist      ║
║ Toulouse, FRANCE                                              ║
║                                                               ║
║   · Expertise & Support 2D, 3D, AR, VR, XR, AI                ║
║   · Product Design & Industrial Design                        ║
║   · Digital communication                                     ║
║   · Immersive experiences  -ᯅ- ✔️                            ║
║                                                               ║
║ · 🡺 https://presentcomposedesign.fr/                         ║
╚═══════════════════════════════════════════════════════════════╝

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#*++==------===**%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++-::::::::::::::::::::::-=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+::::::::::::::::::::::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@%+:::::::::::::::::=++***+=-::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@#=::::::::::::::::+%@@@@@@@@@@%+-:::::::::::::::::::=#@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@#-::::::::::::::::#@@@@@@@@@@@@@@@@%-:::::::::::::::::::=#@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@%=::::::::::::::::*@@@@@@**==-=+##@@@@@*-:::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@=:::::::::::::::::%@@@@@+::::::::::-*@@@@#-::::::::::::::::::::=@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@#::::::::::::::::::%@@@@=::::::::::::::-%@@@#-:::::::::::::::::::::#@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@=::::::::::::::::::*@@@@=::::::::::::::::-%@@@*::::::::::::::::::::::=@@@@@@@@@@@@@@@
@@@@@@@@@@@@@%-::::::::::::::::::-@@@@=::::::::::::::::::-%@@@-::::::::::::::::::::::-%@@@@@@@@@@@@@
@@@@@@@@@@@@#::::::::::::::::::::*@@@#::::::::::::::::::::=@@@*::::::::::::::::::::::::*@@@@@@@@@@@@
@@@@@@@@@@@#:::::::::::::::::::::%@@@+::::::::::::::::::::-@@@%:::::::::::::::::::::::::*@@@@@@@@@@@
@@@@@@@@@@+::::::::::::::::::::::@@@@-:::::::::::::::::::::%@@@::::::::::::::::::::::::::*@@@@@@@@@@
@@@@@@@@@*:::::::::::::::::::::::@@@@=:::::::::::::::::::::@@@@:::::::::::::::::::::::::::*@@@@@@@@@
@@@@@@@@%::::::::::::::::::::::::@@@@*:::::::::::::::::::::@@@%::::::::::::::::::::::::::::*@@@@@@@@
@@@@@@@%:::::::::::::::::::::::::@@@@%::::::::::::::::::::+@@@*:::::::::::::::::::::::::::::%@@@@@@@
@@@@@@@::::::::::::::::::::::::::@@@@@*::::::::::::::::::-@@@@::::::::::::::::::::::::::::::-@@@@@@@
@@@@@@=::::::::::::::::::::::::::@@@@@@*::::::::::::::::-@@@@+:::::::::::::::::::::::::::::::*@@@@@@
@@@@@%:::::::::::::::::::::::::::@@@@@@@*::::::::::::::-%@@@#:::::::::::::::::::::::::::::::::*@@@@@
@@@@@::::::::::::::::::::::::::::@@@@@@@@@*::::::::::+@@@@@*::::::::::::::::::::::::::::::::::-@@@@@
@@@@*::::::::::::::::::::::::::::@@@#=@@@@@@%#*+=**%@@@@@@=::::::::::::::::::::::::::::::::::::*@@@@
@@@@:::::::::::::::::::::::::::::@@@#::*@@@@@@@@@@@@@@@@*:::::::::::::::::::::::::::::::::::::::@@@@
@@@*:::::::::::::::::::::::::::::@@@#::::=*@@@@@@@@@%#=:::::::::::::::::::::::::::::::::::::::::#@@@
@@@=:::::::::::::::::::::::::::::@@@#::::::::-==+=-:::::::::::::::::::::::::::::::::::::::::::::=@@@
@@@::::::::::::::::::::::::::::::@@@#:::::::::::::::::::::::::::::::::::::::::::::::::--:::::::::@@@
@@*::::::::::::::::::::::::::::::@@@#:::::::::+######*:::::::::::::::::::::::::::::::+@=:::::::::#@@
@@*::::::::::::::::::::::::::::::@@@#:::--::::===+*+==:::::=-:::::::=-::::::-::::::::+@=:::::::::+@@
@@:::::::::::::::::::::::::::::::@@@#::+@#@@::-#@@%@%=::=@@@@+:::+@@@@@+-::@@@@%*-::#@@%#:::::::::@@
@@:::::::::::::::::+*##%%#*=-::::@@@#::+@@=::-%@:::-*@=:%@-:=:::*@*:::-@*::@@-:=@%::=*@*=:::::::::@@
@@::::::::::::::+%@@@@@@@@@@@%*-:@@@#::+@*:::*@@@@@@@@#:+@%*-:::@@@@@@@@@-:@%:::#@:::+@=::::::::::@@
@%::::::::::::*@@@@@@@@@@@@@@@@@#+@@#::+@+:::+@=-------:::=%@*::@%-------::@%:::#@:::+@=::::::::::%@
@%::::::::::-@@@@@@++-::::-=#@@@@@+*#::+@+:::-@%=-:+%%-:-=::#@::*@*-::+%=::@%:::#@:::+@=::::::::::#@
@%:::::::::=@@@@%+::::::::::::#@@@@**::+@+::::-#@@@@%=::#@%%@+:::+@@@@@*:::@%:::#@:::+@=::::::::::%@
@%::::::::-@@@@+:::::::::::::::-@@@@+:::-::::::::--:::::::=-:::::::-=-:::::--:::-=----=-::::::::::%@
@@:::::::-@@@@*:::::::::::::::::-%%%*:::::::::::::::::::::::::::::::::::::::::::+%%%%%%#::::::::::@@
@@:::::::*@@@#:::::::+#@%*-::::::=+*#*=+#*=-:::::+#%%#-::::::=#%%#=::::-#@@#-::::=##%#+-::::::::::@@
@@-::::::@@@@-:::::-%@#+*%@*:::::%@#+#@@+*@*::::%@+==#@*::::%@#+=%@*-::%@-=*=:::*@*+=+@%-::::::::-@@
@@+:::::-@@@@::::::#@=::::#@=::::%@::=@*::#@-::*@=::::-@+::*@*::::*@*::*@*-::::-@@####%@#::::::::*@@
@@#:::::-@@@*::::::@@:::::=@*::::%@::=@*::#@-::%@::::::@*::%@-::::-@%:::=%@%-::*@#******+::::::::*@@
@@@-::::-@@@%::::::#@+::::%@-::::%@::=@*::#@-::@@-::::=@-::*@*::::*@*:::-::@%::=@*::::-=-::::::::@@@
@@@+:::::@@@@-::::::%@%*#@@+:::::%@::=@*::#@-::@@@#=+#@+::::*@%*+@@*:::#@*+@*:::*@%*+%@%::::::::-@@@
@@@#:::::#@@@+:::::::=*##+-::::::+*::-*=::+*:::@%=*%#*-::::::=*%#*-:::::=*#+:::::-*##*=--=::::::*@@@
@@@@-::::=@@@@-::::::::::::::::::=**+::::::::::@%:::::::::::::::::::::::-==++**##%%@@@@@@@-::::-@@@@
@@@@*:::::*@@@@-::::::::::::::::+@@@#::::::::::::::::::::::::-==++**##=-#@@@@@@@@@@@@@@@@@=::::*@@@@
@@@@@-:::::#@@@@+-:::::::::::::*@@@@::::::-==++--##%@@@@@@@@@#*#@@%%@@@@@@@@@@@@@@@@@@@#@@@+:::-@@@@
@@@@@%::::::*@@@@@+-:::::::::+@@@@%:=@@@@@@@@@@==@@@**%@@@@*-#@*-@@*@@@*-+**@@@:%@@==@++@@*:::%@@@@@
@@@@@@*::::::=@@@@@@@%%**##@@@@@@=::=@@@@#-:--=-=@@=+@+=@@@:%@@@=+@-*@*-@@@+:@@=#@:*@@%-@@#::+@@@@@@
@@@@@@@-:::::::+%@@@@@@@@@@@@@@#-::::@@@+-%@@@*--@@:@@=*@@@%=*%@@@@*=@-*@@@*:+@=+=#@@@%:@@%:-@@@@@@@
@@@@@@@@-::::::::=*%@@@@@@@##-:::::::@@@:#@@@@@*:@@:%==@@@@@@%+-%@@#-@*+@@@:+:@*:*@@@@@:%@@-@@@@@@@@
@@@@@@@@#-:::::::::::::-:::::::::::::@@%:%@@@@@*-@@-#@@@#-@*%@@@-#@@:@@#=+:%@-#@:@@@@@@*=@@%@@@@@@@@
@@@@@@@@@*:::::::::::::::::::::::::::#@@--@@@@%:*@@%*+*=*@@=+@@@=+@@-#@@@@@@@=#@#@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@*-:::::::::::::::::::::::::#@@@+-==-:#@@@@@@@@@@@@#++*#@@@@@@@#@@@%:@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@*-::::::::::::::::::::::::+@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-=-:+**++==--::%@@@@@@@@@
@@@@@@@@@@@@#-:::::::::::::::::::::::=@@@@@@@@@@@@@@@@@@@@@%%##**++=---::::::::::::::::::::%@@@@@@@@
@@@@@@@@@@@@@@-::::::::::::::::::::::-@@@@@@%###**++=--::::::::::::::::::::::::::::::::::-%@@@@@@@@@
@@@@@@@@@@@@@@@+::::::::::::::::::::::--::::::::::::::::::::::::::::::::::::::::::::::::+@@@@@@@@@@@
@@@@@@@@@@@@@@@@%-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-%@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@+-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@%=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@%=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=%@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@%=-:::::::::::::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@*-:::::::::::::::::::::::::::::::::::::::::::::::::#@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+-:::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*=-:::::::::::::::::::::::::::::::::::+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%**=-:::::::::::::::::::::::::=+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%**++=====+++*##@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#****+++++****##%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+-::::::::::::::::::::==*#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+-::::::::::::::::::::::::::::::==#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-::::::::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@*-::::::::::::::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@#+:::::::::::::::++****%%@@@@@%%##**=--:::::::::::::=#@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@*=:::::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@#*=-:::::::::::=#@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@#=:::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#=-::::::::::=#@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@%=::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*=::::::::::=%@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@*::::::::::*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-:::::::::*%@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@%=::::::::=*@@@@@@@@@@@@@@%#*********#%%@@@@@@@@@@@@@@@@@@@%+-::::::::=%@@@@@@@@@@@@@@
@@@@@@@@@@@@@#:::::::::#@@@@@@@@@@@**+-::::::::::::::::-+#%@%@@@@@@@@@@@@@@%+-::::::::*@@@@@@@@@@@@@
@@@@@@@@@@@@+::::::::+@@@@@@@@@@*-::::::::::::::::::::::#@@@##%%@@@@@@@@@@@@@@+::::::::*%@@@@@@@@@@@
@@@@@@@@@@@=:::::::=#@@@@@@@@@+::::::::::::::::::::::::-*@@@@@@#%%@@@@@@@@@@@@@*-:::::::=%@@@@@@@@@@
@@@@@@@@@@=:::::::*@@@@@@@@@%=::::::::::::::::::::::::::*@@@@@@@@##%@@@@@@@@@@@@%+:::::::=%@@@@@@@@@
@@@@@@@@%=:::::::#@@@@@@@@@%:::::::::::::::::::::::::::+@@@@@@@@@@@%%@@@@@@@@@@@@@*-::::::-%@@@@@@@@
@@@@@@@@=::::::-#@@@@@@@@@%-:::::::::::::::::::::::::==#@@@@@@@@@@@@%#@@@@@@@@@@@@@#-::::::=%@@@@@@@
@@@@@@@=::::::-%@@@@@@@@@@=:::::::::::::::::::::::::*=#%@@@@@@@@@@@@@%#@@@@@@@@@@@@@#-::::::*@@@@@@@
@@@@@@*::::::-#@@@@@@@@@@*::::::::::::::::::::::::*=#+%@@@%@@@@@@@@@@@%%@@@@@@@@@@@@@%-::::::*@@@@@@
@@@@@%:::::::#@@@@@@@@@@%:::::::::::::::::::---:::-:-+*@%%@@@@@@@@@@@@@*%@@@@@@@@@@@@@%-::::::%@@@@@
@@@@@-::::::#@@@@@@@@@@@-::::::::::::::::::::+=#-=#*#=+%%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@#-:::::-%@@@@
@@@@*::::::*@@@@@@@@@@@#:::::::::::::::::::::-++=#==#+-%%%@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@*::::::*@@@@
@@@%::::::-@@@@@@@@@@@@=::::::::::::::::::::::::+=++#%=%*@@@@@@@@@@@@@@@@*@@@@@@@@@@@@@@@-::::::%@@@
@@@*::::::#@@@@@@@@@@@%:::::::::::::::::::::::::+#:+@%+%@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@%-:::::*@@@
@@%::::::=@@@@@@@@@@@@*::::::::::::::::::::::::-#*-#+=@@%@%@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@*::::::%@@
@@*::::::%@@@@@@@@@@@@=:::::::::::::::::::::::+=#@++=+%@@@@@@@@@@@@@@#@@@+-%@@@@@@@@@@@@@@@-:::::*@@
@@::::::*@@@@@@@@@@@@@-:::::::::::::::::::::::-**+@+*=%@%@@@@@@@@@@@#@@%=::*@@@@@@@@@@@@@@@*::::::%@
@%::::::#@@@@@@@@@@@@@::::::::::::::::::::::::::==#@%+@%+*%%@@@@@@@#==+::=-#@@@@@@@@@@@@@@@#::::::*@
@*:::::-@@@@@@@@@@@@@@::::::::::::::::::::::::::::***%-@*@%%@@@@@@@%%=+*%%%@@@@@@@@@@@@@@@@@-:::::+@
@=:::::*@@@@@@@@@@@@@@-::::::::::::::::::::::::::-+@+=+*%*%@@@@@@@%@@@%*=:*@@@@@@@@@@@@@@@@@+:::::=@
%::::::*@@@@@@@@@@@@@@*::::::::::::::::::::::-=-=+#**#=%+@@*@@@@@@@@@@@+=**%@@@@@@@@@@@@@@@@#::::::%
%::::::%@@@@@@@@@@@@@@#:::::::::::::::::::+#@++@%@@#*+*+#=@@@@@@@@@@@@@@*%@#%@@@@@@@@@@@@@@@#::::::#
*::::::@@@@@@@@@@@@@@@@-:::::::::::::::::*@@@:::%@@@@*---**@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@%::::::*
*::::::@@@@@@@@@@@@@@@@+:::::::::::::::::@@@@%::*@@@@@+-:=%+@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@::::::*
*:::::-@@@@@@@@@@@@@@@@#:::::::::::::::::%=%@@-:+@@@@@*::%*@@@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@-:::::*
*:::::=@@@@@@@@@@@@@@@@@+::::::::::::::::*:-@*::*-*@@@@-:-=%@%@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@::::::*
*:::::-@@@@@@@@@@@@@@@@@%-:::::::::::::::*+:%@@:::-@@@@-:=+%%@%@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@::::::*
*::::::%@@@@@@@@@@@@@@@@@*::::::::::::::::*=-@*::::%@@@+:+*@@@%@@@@@@@@@@@%@@%#@@@@@@@@@@@@@%::::::*
#::::::%@@@@@@@@@@@@@@@@@%-::::::::::::::::#+**:::::%@@*:-=%@*@@@@@@@@@@@#**%@@@@@@@@@@@@@@@%::::::#
@::::::*@@@@@@@@@@@@@@@@@@*::::::::::::::::-%@@@@@**@@%=::=+@@@@@%@@@@@@@@@%@@@@@@@@@@@@@@@@*::::::@
@-:::::*@@@@@@@@@@@@@@@@@@@=:::::::::::::::::#@@@@@@@@%:::+=%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@*:::::-@
@+:::::=@@@@@@@@@@@@@@@@@@@%-:::::::::::::::::*%@@@*%@-:::-*=*%@@@@@@@@@@@@@%@@@@@@@@@@@@@@@::::::*@
@*::::::%@@@@@@@@@@@@@@@@@@@*:::::::::::::::::::=%%+#@=:::=*++@@@@@@@@@@@@@#@@@@@@@@@@@@@@@%::::::*@
@@-:::::*@@@@@@@@@@@@@@@@@@@#::::::::::::::::----:=###::::=**%%@@@@@@@@@@@+%@@@@@@@@@@@@@@@+:::::-@@
@@+:::::-%@@@@@@@@@@@@@@@@@@@-:::::::::::::=@@@@@+::::::::-*#%%%@@@@@@@@@%*%@@@@@@@@@@@@@@%::::::*@@
@@#::::::*@@@@@@@@@@@@@@@@@@@+::::::::::::::%@@@@@-:::::::+%@%%%@@@@@@@@@%@@@@@@@@@@@@@@@@+::::::%@@
@@@+::::::%@@@@@@@@@@@@@@@@@@*::::::::::::::*@@@@@-:::::::-+#@%%@%@@@@@@@%@@@@@@@@@@@@@@@%::::::=@@@
@@@%-:::::*@@@@@@@@@@@@@@@@@@*::::::::::::::#@@@@@::::::::::*@%**%@@@@@@@#@@@@@@@@@@@@@@@=::::::%@@@
@@@@*::::::%@@@@@@@@@@@@@@@@@*::::::::::::::*@@@@@#-::::::::===+-%%@@@@@@%%@@@@@@@@@@@@@*::::::*@@@@
@@@@@-:::::-%@@@@@@@@@@@@@@@@+::::::::::::::=#%@@@@*--#=::::::--:=@@%%%@@%@@@@@@@@@@@@@#::::::-@@@@@
@@@@@#-:::::-%@@@@@@@@@@@@@@@=::::::::::::::==@%@%%%#+%%*:::::::-=#%%*%@#*@@@@@@@@@@@@%:::::::#@@@@@
@@@@@@*::::::*%@@@@@@@@@@**+-:::::::::::::::@#@@%@@@%#%@*::::-::::==::%%*@@@@@@@@@@@@%=::::::*@@@@@@
@@@@@@@+::::::*@@@@@@@@*::::::::::::::::::-##%%@#@@@@%%%*-==*%:-::==+**@@@@@@@@@@@@@%=::::::=@@@@@@@
@@@@@@@@-::::::*%@@@@*::::::::::::::::::::::%%%%%@@@@@@@#%@@%%@@@@@@@@@@@@@@@@@@@@@%=::::::=@@@@@@@@
@@@@@@@@%-::::::=%@@%:::::::::::::::::::::#@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#:::::::-@@@@@@@@@
@@@@@@@@@@-::::::-%@#::::::::::::::::::::+@@@@@%@@@@@@@@@@@%%@@@@@@@@@@@@@@@@@@@@*:::::::=@@@@@@@@@@
@@@@@@@@@@@-:::::::*@-:::::::::::::::::::-%@@@@@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@=:::::::=@@@@@@@@@@@
@@@@@@@@@@@@+:::::::==:::::::::::::::::::-%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@#-:::::::+@@@@@@@@@@@@
@@@@@@@@@@@@@*-:::::::::::::::::::::::::::=@@@@@@@@@@@@@@%#@@@@@@@@@@@@@@@@@%=::::::::#@@@@@@@@@@@@@
@@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@+::::::::=#@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@*-::::::::::::::::::::::::::*%@@@@@@@@@@*@@@@@@@@@@@@@@@@+:::::::::*@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@%=:::::::::::::::::::::::::::*%@@@@@@@@#@@@@@@@@@@@@@*=:::::::::=%@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*%@@@@@@@%#@@@@@@@@*+-:::::::::=#@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*%@@@@@@@%@@@@*+:::::::::::=#@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@#=-::::::::::::::::::::::::::+%@@@@%**--::::::::::::+#@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@%*-:::::::::::::::::::::::::::::::::::::::::::::*%@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@#*-:::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##=-:::::::::::::::::::::::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##*=-::::::::::::::::::::-+**%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%##****+++++****%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-->

<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter+Tight:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>

<style>
#xrvu-root {
  all: unset !important; display: block !important; position: relative !important;
  width: 100% !important; height: 520px !important; background: #08080e !important;
  border-radius: 14px !important; overflow: hidden !important;
  font-family: 'Inter Tight', system-ui, -apple-system, sans-serif !important;
  font-size: 13px !important; -webkit-font-smoothing: antialiased;
  color: rgba(255,255,255,.9) !important; line-height: 1.4 !important; box-sizing: border-box !important;
}
#xrvu-root *, #xrvu-root *::before, #xrvu-root *::after { box-sizing: border-box !important; }
#xrvu-root *:not(svg):not(svg *) { font-family: 'Inter Tight', system-ui, -apple-system, sans-serif !important; }
#xrvu-root {
  --xrvu-primary: #0010ef; --xrvu-accent: #1df2d6; --xrvu-text: rgba(255,255,255,.9);
  --xrvu-muted: rgba(255,255,255,.45); --xrvu-dim: rgba(255,255,255,.2);
  --xrvu-glass-bg: rgba(4,6,16,.82); --xrvu-glass-bd: rgba(255,255,255,.12); --xrvu-sep: rgba(255,255,255,.07);
}
#xrvu-gs-stage, #xrvu-three-stage { position: absolute; inset: 0; z-index: 1; }
#xrvu-gs-stage canvas, #xrvu-three-stage canvas { display: block; width: 100% !important; height: 100% !important; touch-action: none; }
#xrvu-bg { position: absolute; inset: 0; z-index: 0; background-size: cover; background-position: center; }
#xrvu-bg-video { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; object-fit: cover; }
#xrvu-overlay { position: absolute; inset: 0; z-index: 30; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; transition: opacity .7s ease; pointer-events: none; }
#xrvu-overlay.fade { opacity: 0; }
#xrvu-overlay.hidden { display: none; }
#xrvu-spinner { width: 38px; height: 38px; border: 2px solid rgba(255,255,255,.05); border-top-color: var(--xrvu-primary); border-right-color: rgba(0,16,239,.2); border-radius: 50%; animation: xrvu-spin .9s linear infinite; }
@keyframes xrvu-spin { to { transform: rotate(360deg); } }
#xrvu-status { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--xrvu-dim); min-height: 14px; }
#xrvu-status.error { color: #e05555; text-transform: none; letter-spacing: 0; font-size: 11px; max-width: 280px; text-align: center; line-height: 1.5; }
#xrvu-barwrap { width: 160px; height: 1px; background: rgba(255,255,255,.07); border-radius: 1px; }
#xrvu-progressbar { height: 100%; width: 0%; background: var(--xrvu-primary); border-radius: 1px; transition: width .15s linear; }
#xrvu-brand { position: absolute; top: 14px; left: 14px; z-index: 20; display: flex; align-items: center; gap: 9px; pointer-events: none; }
#xrvu-brand-logo { max-height: 32px; display: block; }
#xrvu-brand-title { font-size: 14px; font-weight: 700; color: var(--xrvu-text); letter-spacing: .02em; }
#xrvu-bar {
  position: absolute !important; bottom: 10px !important; left: 50% !important; transform: translateX(-50%) !important;
  z-index: 25 !important; display: flex !important; gap: 4px !important; align-items: center !important;
  background: var(--xrvu-glass-bg) !important; backdrop-filter: blur(14px) saturate(1.6) !important;
  -webkit-backdrop-filter: blur(14px) saturate(1.6) !important; border: 1px solid var(--xrvu-glass-bd) !important;
  border-radius: 999px !important; padding: 5px 6px !important; box-shadow: 0 12px 32px rgba(0,0,0,.6) !important;
  margin: 0 !important; list-style: none !important; width: auto !important; max-width: none !important;
  white-space: nowrap !important; transition: opacity .35s ease !important;
}
#xrvu-bar.hud-hidden { opacity: 0 !important; pointer-events: none !important; }
#xrvu-instructions {
  position: absolute !important; bottom: 56px !important; left: 50% !important; transform: translateX(-50%) !important;
  z-index: 24 !important; display: flex !important; gap: 18px !important; pointer-events: none !important;
  transition: opacity .4s ease !important; white-space: nowrap !important;
}
#xrvu-instructions.inst-hidden { opacity: 0 !important; }
#xrvu-root button.xrvu-btn {
  all: unset !important; box-sizing: border-box !important; width: 34px !important; height: 34px !important;
  border-radius: 999px !important; display: flex !important; align-items: center !important; justify-content: center !important;
  cursor: pointer !important; color: var(--xrvu-muted) !important; background: transparent !important;
  transition: background .14s, color .14s, transform .14s !important; padding: 0 !important; margin: 0 !important;
  line-height: 1 !important; outline: none !important; -webkit-appearance: none !important; appearance: none !important; position: relative !important;
}
#xrvu-root button.xrvu-btn:hover { background: rgba(255,255,255,.08) !important; transform: translateY(-1px) !important; color: var(--xrvu-text) !important; }
#xrvu-root button.xrvu-btn.active { color: var(--xrvu-accent) !important; background: rgba(29,242,214,.08) !important; }
#xrvu-root button.xrvu-btn svg { width: 15px; height: 15px; pointer-events: none; flex-shrink: 0; }
#xrvu-btn-anim { width: auto !important; padding: 0 11px !important; gap: 7px !important; font-size: 10px !important; letter-spacing: .07em !important; }
#xrvu-btn-anim svg { width: 13px !important; height: 13px !important; }
.xrvu-sep { width: 1px; background: var(--xrvu-sep); margin: 6px 1px; align-self: stretch; }
#xrvu-anim-menu {
  position: absolute !important; bottom: calc(100% + 10px) !important; left: 50% !important; transform: translateX(-50%) !important;
  z-index: 40 !important; background: var(--xrvu-glass-bg) !important; backdrop-filter: blur(18px) saturate(1.8) !important;
  -webkit-backdrop-filter: blur(18px) saturate(1.8) !important; border: 1px solid var(--xrvu-glass-bd) !important;
  border-radius: 12px !important; padding: 6px !important; min-width: 176px !important;
  display: none !important; flex-direction: column !important; gap: 2px !important;
  box-shadow: 0 16px 40px rgba(0,0,0,.7) !important;
}
#xrvu-anim-menu.open { display: flex !important; }
.xrvu-anim-item { all: unset !important; box-sizing: border-box !important; display: flex !important; align-items: center !important; gap: 9px !important; padding: 7px 10px !important; border-radius: 8px !important; font-size: 11px !important; color: var(--xrvu-muted) !important; cursor: pointer !important; white-space: nowrap !important; transition: background .12s, color .12s !important; }
.xrvu-anim-item:hover { background: rgba(255,255,255,.07) !important; color: var(--xrvu-text) !important; }
.xrvu-anim-item.active { color: var(--xrvu-accent) !important; background: rgba(29,242,214,.07) !important; }
.xrvu-anim-item svg { width: 13px; height: 13px; flex-shrink: 0; pointer-events: none; }
#xrvu-panel-transform, #xrvu-panel-settings, #xrvu-panel-media, #xrvu-panel-triggers {
  position: absolute !important; bottom: 58px !important; left: 50% !important; transform: translateX(-50%) !important;
  z-index: 35 !important; background: var(--xrvu-glass-bg) !important; backdrop-filter: blur(18px) saturate(1.8) !important;
  -webkit-backdrop-filter: blur(18px) saturate(1.8) !important; border: 1px solid var(--xrvu-glass-bd) !important;
  border-radius: 14px !important; padding: 14px 16px !important; min-width: 260px !important;
  display: none !important; flex-direction: column !important; gap: 10px !important; box-shadow: 0 16px 40px rgba(0,0,0,.7) !important;
}
#xrvu-panel-media { min-width: 290px !important; max-height: 72vh !important; overflow-y: auto !important; }
#xrvu-panel-triggers { left: auto !important; right: 12px !important; transform: none !important; min-width: 230px !important; }
#xrvu-panel-transform.open, #xrvu-panel-settings.open, #xrvu-panel-media.open, #xrvu-panel-triggers.open { display: flex !important; }
.xrvu-panel-title { font-size: 9px !important; letter-spacing: .12em !important; text-transform: uppercase !important; color: var(--xrvu-dim) !important; margin-bottom: 2px !important; }
.xrvu-panel-subtitle { font-size: 9px !important; letter-spacing: .09em !important; text-transform: uppercase !important; color: var(--xrvu-accent) !important; }
.xrvu-row { display: flex !important; align-items: center !important; gap: 8px !important; }
.xrvu-row label { font-size: 10px !important; color: var(--xrvu-dim) !important; width: 46px !important; flex-shrink: 0 !important; text-align: right !important; }
.xrvu-row input[type=range] { all: unset !important; flex: 1 !important; height: 2px !important; background: rgba(255,255,255,.14) !important; border-radius: 2px !important; cursor: pointer !important; -webkit-appearance: none !important; appearance: none !important; accent-color: var(--xrvu-accent) !important; }
.xrvu-row input[type=range]::-webkit-slider-thumb { -webkit-appearance: none !important; width: 12px !important; height: 12px !important; border-radius: 50% !important; background: var(--xrvu-accent) !important; cursor: pointer !important; }
.xrvu-row input[type=range]::-moz-range-thumb { width: 12px !important; height: 12px !important; border-radius: 50% !important; background: var(--xrvu-accent) !important; border: none !important; cursor: pointer !important; }
.xrvu-val { font-size: 9px !important; color: var(--xrvu-muted) !important; width: 32px !important; text-align: right !important; flex-shrink: 0 !important; font-variant-numeric: tabular-nums !important; }
#xrvu-lock-btn { all: unset !important; box-sizing: border-box !important; width: 22px !important; height: 22px !important; border-radius: 5px !important; border: 1px solid var(--xrvu-glass-bd) !important; display: flex !important; align-items: center !important; justify-content: center !important; cursor: pointer !important; color: var(--xrvu-dim) !important; flex-shrink: 0 !important; transition: color .14s, border-color .14s !important; }
#xrvu-lock-btn svg { width: 11px; height: 11px; }
#xrvu-lock-btn.locked { color: var(--xrvu-accent) !important; border-color: var(--xrvu-accent) !important; }
.xrvu-panel-sep { height: 1px; background: var(--xrvu-sep); margin: 2px 0; }
.xrvu-num-input { all: unset !important; box-sizing: border-box !important; width: 58px !important; padding: 2px 5px !important; background: rgba(255,255,255,.06) !important; border: 1px solid rgba(255,255,255,.1) !important; border-radius: 5px !important; font-size: 9px !important; color: var(--xrvu-text) !important; text-align: right !important; cursor: text !important; font-variant-numeric: tabular-nums !important; -moz-appearance: textfield !important; }
.xrvu-num-input::-webkit-inner-spin-button, .xrvu-num-input::-webkit-outer-spin-button { -webkit-appearance: none !important; }
.xrvu-num-input:focus { border-color: var(--xrvu-accent) !important; outline: none !important; }
.xrvu-url-input { all: unset !important; box-sizing: border-box !important; width: 100% !important; padding: 6px 10px !important; background: rgba(255,255,255,.06) !important; border: 1px solid rgba(255,255,255,.1) !important; border-radius: 8px !important; font-size: 10px !important; color: var(--xrvu-text) !important; cursor: text !important; }
.xrvu-url-input::placeholder { color: var(--xrvu-dim) !important; }
.xrvu-url-input:focus { border-color: var(--xrvu-accent) !important; outline: none !important; }
.xrvu-proj-row { display: flex !important; gap: 4px !important; flex-wrap: wrap !important; }
.xrvu-proj-btn { all: unset !important; box-sizing: border-box !important; padding: 3px 9px !important; border-radius: 6px !important; border: 1px solid var(--xrvu-glass-bd) !important; font-size: 9px !important; color: var(--xrvu-muted) !important; cursor: pointer !important; transition: all .12s !important; }
.xrvu-proj-btn:hover { background: rgba(255,255,255,.07) !important; color: var(--xrvu-text) !important; }
.xrvu-proj-btn.active { background: rgba(29,242,214,.1) !important; color: var(--xrvu-accent) !important; border-color: var(--xrvu-accent) !important; }
.xrvu-apply-btn { all: unset !important; box-sizing: border-box !important; width: 100% !important; padding: 6px 0 !important; border-radius: 8px !important; background: rgba(0,16,239,.25) !important; border: 1px solid rgba(0,16,239,.5) !important; font-size: 10px !important; color: var(--xrvu-text) !important; cursor: pointer !important; text-align: center !important; transition: background .12s !important; }
.xrvu-apply-btn:hover { background: rgba(0,16,239,.42) !important; }
.xrvu-apply-btn.danger { background: rgba(180,20,20,.25) !important; border-color: rgba(180,20,20,.5) !important; }
.xrvu-apply-btn.danger:hover { background: rgba(180,20,20,.45) !important; }
#xrvu-btn-sound { position: absolute !important; bottom: 14px !important; left: 14px !important; z-index: 25 !important; all: unset !important; box-sizing: border-box !important; width: 34px !important; height: 34px !important; border-radius: 999px !important; display: flex !important; align-items: center !important; justify-content: center !important; cursor: pointer !important; color: var(--xrvu-muted) !important; background: var(--xrvu-glass-bg) !important; backdrop-filter: blur(14px) !important; -webkit-backdrop-filter: blur(14px) !important; border: 1px solid var(--xrvu-glass-bd) !important; box-shadow: 0 8px 24px rgba(0,0,0,.5) !important; transition: color .14s, transform .14s !important; }
#xrvu-btn-sound svg { width: 15px; height: 15px; pointer-events: none; }
#xrvu-btn-sound:hover { transform: translateY(-1px) !important; color: var(--xrvu-text) !important; }
#xrvu-btn-sound.active { color: var(--xrvu-accent) !important; }
#xrvu-qr-panel { position: absolute; bottom: 58px; right: 12px; z-index: 26; background: var(--xrvu-glass-bg); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border: 1px solid var(--xrvu-glass-bd); border-radius: 14px; padding: 10px; text-align: center; display: none; }
#xrvu-qr-panel p { font-size: 9px; color: var(--xrvu-muted); letter-spacing: .08em; text-transform: uppercase; margin-top: 6px; }
#xrvu-reticule { position: absolute; inset: 0; z-index: 15; display: none; align-items: center; justify-content: center; pointer-events: none; }
#xrvu-reticule svg { width: 80px; height: 80px; opacity: .7; }
.xrvu-toast { position: absolute; bottom: 70px; left: 50%; transform: translateX(-50%); z-index: 40; background: var(--xrvu-glass-bg); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--xrvu-glass-bd); border-radius: 12px; padding: 9px 18px; font-size: 11px; color: var(--xrvu-muted); pointer-events: none; white-space: nowrap; animation: xrvu-fadeup .25s ease; }
@keyframes xrvu-fadeup { from { opacity:0; transform: translateX(-50%) translateY(8px); } }
.xrvu-hint { font-size: 9px; color: rgba(255,255,255,.25); letter-spacing: .06em; text-transform: uppercase; }
.xrvu-hint b { font-weight: 500; color: rgba(255,255,255,.4); background: rgba(255,255,255,.07); border: 1px solid rgba(255,255,255,.1); border-radius: 3px; padding: 1px 5px; margin-right: 3px; }
#xrvu-gps-coords { font-size: 9px !important; color: var(--xrvu-dim) !important; font-variant-numeric: tabular-nums !important; }
@media (max-width: 480px) {
  #xrvu-root { height: 380px !important; }
  #xrvu-bar { padding: 4px !important; gap: 2px !important; }
  #xrvu-root button.xrvu-btn { width: 30px !important; height: 30px !important; }
  #xrvu-btn-anim { padding: 0 8px !important; font-size: 9px !important; }
  #xrvu-panel-transform, #xrvu-panel-settings, #xrvu-panel-media { min-width: 200px !important; padding: 10px 12px !important; }
}
</style>

<div id="xrvu-root">
  <video id="xrvu-bg-video" autoplay muted loop playsinline style="display:none;"></video>
  <div id="xrvu-bg"></div>
  <div id="xrvu-gs-stage"    style="display:none;"></div>
  <div id="xrvu-three-stage" style="display:none;"></div>

  <div id="xrvu-overlay">
    <div id="xrvu-spinner"></div>
    <div id="xrvu-status">Initialisation</div>
    <div id="xrvu-barwrap"><div id="xrvu-progressbar"></div></div>
  </div>

  <div id="xrvu-brand" style="display:none;">
    <img decoding="async" id="xrvu-brand-logo" src="" alt="logo"/>
    <span id="xrvu-brand-title"></span>
  </div>

  <div id="xrvu-reticule">
    <svg viewBox="0 0 80 80" fill="none">
      <circle cx="40" cy="40" r="30" stroke="#1df2d6" stroke-width="1.5" stroke-dasharray="4 4"/>
      <line x1="40" y1="10" x2="40" y2="20" stroke="#1df2d6" stroke-width="1.5"/>
      <line x1="40" y1="60" x2="40" y2="70" stroke="#1df2d6" stroke-width="1.5"/>
      <line x1="10" y1="40" x2="20" y2="40" stroke="#1df2d6" stroke-width="1.5"/>
      <line x1="60" y1="40" x2="70" y2="40" stroke="#1df2d6" stroke-width="1.5"/>
    </svg>
  </div>

  <div id="xrvu-qr-panel"><div id="xrvu-qr-code"></div><p>Ouvrir en AR / VR</p></div>

  <button id="xrvu-btn-sound" style="display:none;" title="Son">
    <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><polygon points="7,3 3.5,6 2,6 2,10 3.5,10 7,13" fill="currentColor" stroke="currentColor" stroke-width="1"/><path d="M10 5.5a3.5 3.5 0 0 1 0 5M12 3a6.5 6.5 0 0 1 0 10"/></svg>
  </button>

  <div id="xrvu-panel-transform">
    <div class="xrvu-panel-title">Position &amp; Echelle</div>
    <div class="xrvu-row"><label>X</label><input type="range" id="xrvu-tx" min="-5" max="5" step="0.01" value="0"><span class="xrvu-val" id="xrvu-tx-val">0.00</span></div>
    <div class="xrvu-row"><label>Y</label><input type="range" id="xrvu-ty" min="-5" max="5" step="0.01" value="0"><span class="xrvu-val" id="xrvu-ty-val">0.00</span></div>
    <div class="xrvu-row"><label>Z</label><input type="range" id="xrvu-tz" min="-5" max="5" step="0.01" value="0"><span class="xrvu-val" id="xrvu-tz-val">0.00</span></div>
    <div class="xrvu-panel-sep"></div>
    <div class="xrvu-row">
      <label>Echelle</label>
      <input type="range" id="xrvu-tscale" min="-2" max="3" step="0.001" value="0">
      <input type="number" id="xrvu-tscale-num" class="xrvu-num-input" value="1.000" step="0.001">
      <button id="xrvu-lock-btn" class="locked" title="Proportions">
        <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="7" width="10" height="8" rx="1.5"/><path d="M5 7V5.5a3 3 0 0 1 6 0V7"/></svg>
      </button>
    </div>
  </div>

  <div id="xrvu-panel-settings">
    <div class="xrvu-panel-title">Reglages</div>
    <div class="xrvu-row"><label>Ambiant</label><input type="range" id="xrvu-s-ambient" min="0" max="2" step="0.01" value="0.7"><span class="xrvu-val" id="xrvu-s-ambient-val">0.70</span></div>
    <div class="xrvu-row"><label>Lumiere</label><input type="range" id="xrvu-s-light" min="0" max="3" step="0.01" value="0.9"><span class="xrvu-val" id="xrvu-s-light-val">0.90</span></div>
    <div class="xrvu-panel-sep"></div>
    <div class="xrvu-row"><label>Opacite</label><input type="range" id="xrvu-s-opacity" min="0" max="1" step="0.01" value="1"><span class="xrvu-val" id="xrvu-s-opacity-val">1.00</span></div>
    <div class="xrvu-row"><label>Brillance</label><input type="range" id="xrvu-s-roughness" min="0" max="1" step="0.01" value="0.4"><span class="xrvu-val" id="xrvu-s-roughness-val">0.40</span></div>
    <div class="xrvu-row"><label>Reflexion</label><input type="range" id="xrvu-s-metalness" min="0" max="1" step="0.01" value="0.2"><span class="xrvu-val" id="xrvu-s-metalness-val">0.20</span></div>
  </div>

  <div id="xrvu-panel-media">
    <div class="xrvu-panel-title">Medias</div>
    <div class="xrvu-panel-subtitle">Video</div>
    <input type="text" id="xrvu-mv-url" class="xrvu-url-input" placeholder="URL video (mp4, webm...)">
    <div class="xrvu-proj-row" id="xrvu-mv-proj">
      <button class="xrvu-proj-btn active" data-proj="flat">Plat</button>
      <button class="xrvu-proj-btn" data-proj="sphere">360 Sphere</button>
      <button class="xrvu-proj-btn" data-proj="cylinder">Cylindrique</button>
      <button class="xrvu-proj-btn" data-proj="cube">Cubique</button>
    </div>
    <div class="xrvu-row"><label>Taille</label><input type="range" id="xrvu-mv-size" min="0.5" max="20" step="0.1" value="3"><span class="xrvu-val" id="xrvu-mv-size-val">3.0</span></div>
    <button class="xrvu-apply-btn" id="xrvu-mv-apply">Charger video</button>
    <button class="xrvu-apply-btn danger" id="xrvu-mv-remove" style="display:none;">Retirer video</button>
    <div class="xrvu-panel-sep"></div>
    <div class="xrvu-panel-subtitle">Image</div>
    <input type="text" id="xrvu-mi-url" class="xrvu-url-input" placeholder="URL image (jpg, png, webp...)">
    <div class="xrvu-proj-row" id="xrvu-mi-proj">
      <button class="xrvu-proj-btn active" data-proj="flat">Plat</button>
      <button class="xrvu-proj-btn" data-proj="sphere">360 Sphere</button>
      <button class="xrvu-proj-btn" data-proj="cylinder">Cylindrique</button>
      <button class="xrvu-proj-btn" data-proj="cube">Cubique</button>
    </div>
    <div class="xrvu-row"><label>Taille</label><input type="range" id="xrvu-mi-size" min="0.5" max="20" step="0.1" value="3"><span class="xrvu-val" id="xrvu-mi-size-val">3.0</span></div>
    <button class="xrvu-apply-btn" id="xrvu-mi-apply">Charger image</button>
    <button class="xrvu-apply-btn danger" id="xrvu-mi-remove" style="display:none;">Retirer image</button>
    <div class="xrvu-panel-sep"></div>
    <div class="xrvu-panel-subtitle">Audio</div>
    <input type="text" id="xrvu-ma-url" class="xrvu-url-input" placeholder="URL audio (mp3, ogg...)">
    <div class="xrvu-row"><label>Volume</label><input type="range" id="xrvu-ma-vol" min="0" max="1" step="0.01" value="0.8"><span class="xrvu-val" id="xrvu-ma-vol-val">0.80</span></div>
    <button class="xrvu-apply-btn" id="xrvu-ma-apply">Charger audio</button>
  </div>

  <div id="xrvu-panel-triggers">
    <div class="xrvu-panel-title">Triggers XR</div>
    <div class="xrvu-panel-subtitle">GPS</div>
    <div id="xrvu-gps-coords">---, ---</div>
    <div class="xrvu-row"><label style="width:auto;">Rayon m</label><input type="range" id="xrvu-gps-radius" min="5" max="500" step="5" value="50"><span class="xrvu-val" id="xrvu-gps-radius-val">50</span></div>
    <input type="text" id="xrvu-gps-zone-url" class="xrvu-url-input" placeholder="URL contenu a declencher">
    <input type="text" id="xrvu-gps-zone-name" class="xrvu-url-input" style="margin-top:4px;" placeholder="Nom de la zone GPS">
    <div style="display:flex;gap:4px;">
      <button class="xrvu-apply-btn" id="xrvu-gps-watch" style="font-size:9px;">Activer GPS</button>
      <button class="xrvu-apply-btn" id="xrvu-gps-add" style="font-size:9px;">+ Zone ici</button>
    </div>
    <div id="xrvu-gps-zones-list" style="font-size:9px;color:var(--xrvu-dim);max-height:80px;overflow-y:auto;"></div>
    <div class="xrvu-panel-sep"></div>
    <div class="xrvu-panel-subtitle">Image Tracker</div>
    <input type="text" id="xrvu-it-url" class="xrvu-url-input" placeholder="URL image cible (jpg/png)">
    <div class="xrvu-row"><label style="width:auto;">Largeur m</label><input type="range" id="xrvu-it-width" min="0.05" max="1" step="0.01" value="0.2"><span class="xrvu-val" id="xrvu-it-width-val">0.20</span></div>
    <input type="text" id="xrvu-it-content" class="xrvu-url-input" style="margin-top:4px;" placeholder="URL contenu (modele, video...)">
    <button class="xrvu-apply-btn" id="xrvu-it-add">Ajouter tracker</button>
    <div id="xrvu-it-list" style="font-size:9px;color:var(--xrvu-dim);"></div>
  </div>

  <div id="xrvu-bar">
    <div style="position:relative;">
      <button class="xrvu-btn" id="xrvu-btn-anim" title="Animations">
        <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="1.5" y="3.5" width="13" height="9" rx="1.5"/><path d="M5 3.5v9M11 3.5v9M1.5 6.5h3M11.5 6.5h3M1.5 9.5h3M11.5 9.5h3"/></svg>
        &nbsp;Anim
      </button>
      <div id="xrvu-anim-menu">
        <button class="xrvu-anim-item" data-mode="none"><svg viewBox="0 0 16 16" fill="currentColor"><rect x="4" y="4" width="8" height="8" rx="1.5"/></svg>Aucune</button>
        <button class="xrvu-anim-item" data-mode="turntable"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2.5a5.5 5.5 0 1 0 5.5 5.5"/><path d="M11 1l3 1.5-1.5 3"/></svg>Tourniquet</button>
        <button class="xrvu-anim-item" data-mode="floating"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><path d="M.5 8c1.5-3.5 3-3.5 4.5 0s3 3.5 4.5 0 3-3.5 4.5 0"/></svg>Flottement</button>
        <button class="xrvu-anim-item" data-mode="breathing"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2.5v5M5 7.5C3.5 7.5 2 8.5 2 10.5s1 3 2.5 3S6.5 12.5 6.5 10.5V7.5M11 7.5c1.5 0 3 1 3 3s-1 3-2.5 3S9.5 12.5 9.5 10.5V7.5"/></svg>Respiration</button>
        <button class="xrvu-anim-item" data-mode="expandcontract"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M1 6V1h5M15 6V1h-5M1 10v5h5M15 10v5h-5"/></svg>Expansion</button>
        <button class="xrvu-anim-item" data-mode="followmouse"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="1.5" width="6" height="10" rx="3"/><line x1="8" y1="1.5" x2="8" y2="5.5"/></svg>Suivre souris</button>
        <button class="xrvu-anim-item" data-mode="smoothorbit"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4"><circle cx="8" cy="8" r="6.5"/><circle cx="8" cy="8" r="2" fill="currentColor" stroke="none"/></svg>Orbite douce</button>
        <button class="xrvu-anim-item" data-mode="rotateonscroll"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M14 8A6 6 0 1 1 11 3"/><path d="M14 3v5h-5"/></svg>Scroll</button>
        <button class="xrvu-anim-item" data-mode="pulsezoom"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><circle cx="6.5" cy="6.5" r="5"/><path d="M6.5 4.5v4M4.5 6.5h4M13 13l-3.5-3.5"/></svg>Zoom pulse</button>
        <button class="xrvu-anim-item" data-mode="clickfade"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><path d="M2 2l12 12M6.5 6.7A3 3 0 0 0 9.3 9.5"/><path d="M1 8s2.5-4.5 7-4.5c.9 0 1.7.1 2.5.4"/><path d="M13.5 9.8C12.1 11.5 10.1 12.5 8 12.5c-4.5 0-7-4.5-7-4.5"/></svg>Apparition</button>
      </div>
    </div>
    <div class="xrvu-sep"></div>
    <button class="xrvu-btn" id="xrvu-btn-transform" title="Position / Echelle">
      <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><line x1="1" y1="4" x2="15" y2="4"/><line x1="1" y1="8" x2="15" y2="8"/><line x1="1" y1="12" x2="15" y2="12"/><circle cx="5" cy="4" r="1.8" fill="currentColor" stroke="none"/><circle cx="10" cy="8" r="1.8" fill="currentColor" stroke="none"/><circle cx="6" cy="12" r="1.8" fill="currentColor" stroke="none"/></svg>
    </button>
    <button class="xrvu-btn" id="xrvu-btn-settings" title="Reglages">
      <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><circle cx="8" cy="8" r="2.5"/><path d="M8 1.5v2M8 12.5v2M1.5 8h2M12.5 8h2M3.6 3.6l1.4 1.4M11 11l1.4 1.4M3.6 12.4l1.4-1.4M11 5l1.4-1.4"/></svg>
    </button>
    <button class="xrvu-btn" id="xrvu-btn-media" title="Medias — video, image, audio">
      <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="3" width="14" height="10" rx="1.5"/><path d="M6.5 6l4 2.5-4 2.5V6z" fill="currentColor" stroke="none"/></svg>
    </button>
    <div class="xrvu-sep"></div>
    <button class="xrvu-btn" id="xrvu-btn-ar" title="Realite Augmentee" style="display:none;">
      <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="1" width="8" height="14" rx="2"/><line x1="6" y1="3.5" x2="10" y2="3.5"/><circle cx="8" cy="12.5" r=".8" fill="currentColor" stroke="none"/></svg>
    </button>
    <button class="xrvu-btn" id="xrvu-btn-vr" title="Mode VR" style="display:none;">
      <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="5" width="14" height="7" rx="2"/><circle cx="5.5" cy="8.5" r="1.8"/><circle cx="10.5" cy="8.5" r="1.8"/><line x1="7.3" y1="8.5" x2="8.7" y2="8.5"/></svg>
    </button>
    <button class="xrvu-btn" id="xrvu-btn-triggers" title="Triggers GPS / Image tracker">
      <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="7" r="3"/><path d="M8 1v2M8 12v3M1 7h2M12 7h3M8 10v2"/></svg>
    </button>
    <button class="xrvu-btn" id="xrvu-btn-qr" title="QR Code">
      <svg viewBox="0 0 16 16" fill="currentColor"><path fill-rule="evenodd" d="M1 1h6v6H1V1zm1.5 1.5v3h3v-3h-3z"/><path fill-rule="evenodd" d="M9 1h6v6H9V1zm1.5 1.5v3h3v-3h-3z"/><path fill-rule="evenodd" d="M1 9h6v6H1V9zm1.5 1.5v3h3v-3h-3z"/><rect x="9" y="9" width="2" height="2"/><rect x="13" y="9" width="2" height="2"/><rect x="9" y="13" width="6" height="2"/><rect x="11" y="11" width="2" height="2"/></svg>
    </button>
    <button class="xrvu-btn" id="xrvu-btn-fs" title="Plein ecran">
      <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M1 6V2h4M15 6V2h-4M1 10v4h4M15 10v4h-4"/></svg>
    </button>
  </div>

  <div id="xrvu-instructions">
    <span class="xrvu-hint"><b>Glisser</b>Rotation</span>
    <span class="xrvu-hint"><b>Scroll</b>Zoom</span>
    <span class="xrvu-hint"><b>Shift+drag</b>Pan</span>
    <span class="xrvu-hint"><b>Dbl-clic</b>Reset</span>
  </div>
</div>

<script type="importmap">
{
  "imports": {
    "three":         "https://cdn.jsdelivr.net/npm/three@0.167.0/build/three.module.js",
    "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.167.0/examples/jsm/",
    "gsplat":        "https://cdn.jsdelivr.net/npm/gsplat@1.2.9/dist/index.es.js"
  }
}
</script>

<script type="module">
import * as THREE                   from "three";
import { OrbitControls }            from "three/addons/controls/OrbitControls.js";
import { GLTFLoader }               from "three/addons/loaders/GLTFLoader.js";
import { OBJLoader }                from "three/addons/loaders/OBJLoader.js";
import { FBXLoader }                from "three/addons/loaders/FBXLoader.js";
import { STLLoader }                from "three/addons/loaders/STLLoader.js";
import { XRButton }                 from "three/addons/webxr/XRButton.js";
import { XRControllerModelFactory } from "three/addons/webxr/XRControllerModelFactory.js";
import { OculusHandModel }          from "three/addons/webxr/OculusHandModel.js";

const ICONS = {
  expand:    `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M1 6V2h4M15 6V2h-4M1 10v4h4M15 10v4h-4"/></svg>`,
  compress:  `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 1v4H1M11 1v4h4M5 15v-4H1M11 15v-4h4"/></svg>`,
  volumeOn:  `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><polygon points="7,3 3.5,6 2,6 2,10 3.5,10 7,13" fill="currentColor" stroke="currentColor" stroke-width="1"/><path d="M10 5.5a3.5 3.5 0 0 1 0 5M12 3a6.5 6.5 0 0 1 0 10"/></svg>`,
  volumeOff: `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><polygon points="7,3 3.5,6 2,6 2,10 3.5,10 7,13" fill="currentColor" stroke="currentColor" stroke-width="1"/><path d="M11 7l3 3M14 7l-3 3"/></svg>`,
  lock:      `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="7" width="10" height="8" rx="1.5"/><path d="M5 7V5.5a3 3 0 0 1 6 0V7"/></svg>`,
  lockOpen:  `<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="7" width="10" height="8" rx="1.5"/><path d="M5 7V5.5a3 3 0 0 1 6 0"/></svg>`,
};

/* ═══════════════════════════════════════════════
   CONFIG — modifier uniquement cette section
   ═══════════════════════════════════════════════ */
const CONFIG = {
  model:      { url: 'https://presentcomposedesign.fr/wp-content/uploads/2026/04/Oak-seed-hyper3dai_basic_pbr_PCdlab.glb', format: 'auto' },
  background: { color: '#08080e', opacity: 1.0, image: null, video: null },
  overlay:    { logo: null, title: null, titleColor: '#ffffff' },
  commands:   { display: true },
  animation:  { mode: 'followmouse', speed: 0.4 },
  transform:  { x: 0, y: 0, z: 0, scale: 1.0 },
  lights:     { ambient: 0.7, directional: 0.9 },
  material:   { opacity: 1.0, roughness: 0.4, metalness: 0.2 },
  media:      { sound: null, soundAutoplay: false, soundLoop: true, image: null },
  xr:         { ar: true, vr: true, gyroscope: true, hitTest: true },
  editorMode: true,
  hud:        { autoHide: true, autoHideDelay: 1500 },
  vr:         { handInteractions: true, teleport: true },
  triggers:   { gps: { enabled: false, radius: 50, zones: [] }, imageTracker: { enabled: false, targets: [] } },
};

/* ─── Helpers ─── */
const $ = id => document.getElementById(id);
const lbl = t   => { $('xrvu-status').className=''; $('xrvu-status').textContent=t; };
const prg = p   => { $('xrvu-progressbar').style.width=Math.min(100,Math.round(p*100))+'%'; };
const err = msg => { $('xrvu-spinner').style.cssText='animation:none;border-top-color:rgba(224,85,85,.4)'; $('xrvu-status').className='error'; $('xrvu-status').textContent=msg; console.error('[XRVU]',msg); };
function toast(msg,ms=2400){ const t=document.createElement('div'); t.className='xrvu-toast'; t.textContent=msg; $('xrvu-root').appendChild(t); setTimeout(()=>{ t.style.opacity='0'; t.style.transition='opacity .35s'; setTimeout(()=>t.remove(),380); },ms); }
function overlayFade(){ const o=$('xrvu-overlay'); o.classList.add('fade'); setTimeout(()=>o.classList.add('hidden'),800); }

/* ─── HUD auto-hide ─── */
let _firstInteraction=false, _hudTimer=null;
function onAnyInteraction(){
  if(!_firstInteraction){
    _firstInteraction=true;
    const inst=$('xrvu-instructions');
    if(inst){ inst.classList.add('inst-hidden'); setTimeout(()=>inst.style.display='none',450); }
  }
  if(!CONFIG.hud.autoHide) return;
  const bar=$('xrvu-bar');
  bar.classList.remove('hud-hidden');
  clearTimeout(_hudTimer);
  _hudTimer=setTimeout(()=>bar.classList.add('hud-hidden'), CONFIG.hud.autoHideDelay);
}
['mousemove','touchstart','click','keydown'].forEach(ev=>
  $('xrvu-root').addEventListener(ev, onAnyInteraction, {passive:true})
);

/* ═══════════════════════════════════════════════
   ENGINE Three.js
   ═══════════════════════════════════════════════ */
let threeRenderer, threeScene, threeCamera, threeControls, threeModelGroup=null;
let ambientLight, keyLight, fillLight;
let xrHitTestSource=null, xrRefSpace=null, xrSession=null, hand1, hand2;

function initThree(){
  const container=$('xrvu-three-stage');
  const wasHidden=container.style.display==='none';
  if(wasHidden) container.style.visibility='hidden';
  container.style.display='block';
  const W=container.clientWidth||$('xrvu-root').clientWidth||800;
  const H=container.clientHeight||$('xrvu-root').clientHeight||520;
  if(wasHidden){ container.style.display='none'; container.style.visibility=''; }
  threeScene=new THREE.Scene(); applyBackground();
  threeCamera=new THREE.PerspectiveCamera(55,W/H,0.01,2000); threeCamera.position.set(0,0.5,3);
  threeRenderer=new THREE.WebGLRenderer({antialias:true,alpha:true,premultipliedAlpha:false});
  threeRenderer.setSize(W,H); threeRenderer.setPixelRatio(Math.min(2,devicePixelRatio));
  threeRenderer.xr.enabled=true; threeRenderer.shadowMap.enabled=true; threeRenderer.shadowMap.type=THREE.PCFSoftShadowMap;
  container.appendChild(threeRenderer.domElement);
  ambientLight=new THREE.AmbientLight(0xffffff,CONFIG.lights.ambient); threeScene.add(ambientLight);
  keyLight=new THREE.DirectionalLight(0xffffff,CONFIG.lights.directional); keyLight.position.set(5,10,7); keyLight.castShadow=true; threeScene.add(keyLight);
  fillLight=new THREE.DirectionalLight(0x8899ff,0.3); fillLight.position.set(-5,5,-5); threeScene.add(fillLight);
  threeControls=new OrbitControls(threeCamera,threeRenderer.domElement);
  threeControls.enableDamping=true; threeControls.dampingFactor=0.06;
  threeControls.addEventListener('start', onAnyInteraction);
  threeControls.addEventListener('start', onUserInteract);
  setupXRButtons();
  const cmf=new XRControllerModelFactory();
  [0,1].forEach(i=>{ const g=threeRenderer.xr.getControllerGrip(i); g.add(cmf.createControllerModel(g)); threeScene.add(g); });
  hand1=threeRenderer.xr.getHand(0); hand1.add(new OculusHandModel(hand1)); threeScene.add(hand1);
  hand2=threeRenderer.xr.getHand(1); hand2.add(new OculusHandModel(hand2)); threeScene.add(hand2);
  setupVRInteractions();
  new ResizeObserver(()=>{ const w=container.clientWidth,h=container.clientHeight; threeCamera.aspect=w/h; threeCamera.updateProjectionMatrix(); threeRenderer.setSize(w,h); }).observe(container);
  threeRenderer.setAnimationLoop(threeLoop);
}

function applyBackground(){
  if(!threeScene) return;
  const c=CONFIG.background;
  if(c.color&&c.opacity>0){ const col=new THREE.Color(c.color); threeRenderer?.setClearColor(col,c.opacity); threeScene.background=c.opacity===1?col:null; }
  else { threeRenderer?.setClearColor(0x000000,0); threeScene.background=null; }
  if(c.image){ $('xrvu-bg').style.backgroundImage=`url(${c.image})`; $('xrvu-bg').style.opacity=String(1-(c.opacity||0)); }
  if(c.video){ const v=$('xrvu-bg-video'); v.src=c.video; v.style.display='block'; v.style.opacity=String(1-(c.opacity||0)); }
}

/* ═══════════════════════════════════════════════
   ENGINE Gaussian Splats
   ═══════════════════════════════════════════════ */
let GSRenderer=null,GSScene=null,GSCamera=null,GSOrbitControls=null,GSLoader=null,_gsplat_ready=false;
async function loadGsplatLib(){
  if(_gsplat_ready) return true;
  try {
    const gs=await import("gsplat");
    GSRenderer=gs.WebGLRenderer||gs.Renderer||gs.default?.WebGLRenderer||gs.default?.Renderer;
    GSScene=gs.Scene||gs.default?.Scene; GSCamera=gs.Camera||gs.default?.Camera;
    GSOrbitControls=gs.OrbitControls||gs.Controls||gs.default?.OrbitControls; GSLoader=gs.Loader||gs.default?.Loader;
    if(!GSRenderer||!GSLoader) throw new Error('exports manquants');
    _gsplat_ready=true; return true;
  } catch(e){ console.warn('[XRVU] gsplat:',e.message); return false; }
}

let gsRenderer,gsScene,gsCamera,gsControls;
let gsSceneRadius=1.0,gsCamInitialized=false,gsAnim_angle=0;
const GS_MS=1000/30; let gsLastFrameTime=0;
const GS_CLK={prev:0};

async function initGS(){
  const ok=await loadGsplatLib(); if(!ok) return;
  const container=$('xrvu-gs-stage');
  try {
    const gsCanvas=document.createElement('canvas');
    gsCanvas.style.cssText='width:100%;height:100%;display:block;touch-action:none;';
    container.appendChild(gsCanvas);
    gsRenderer=new GSRenderer(gsCanvas); gsScene=new GSScene();
    gsCamera=GSCamera?new GSCamera():null;
    gsControls=(GSOrbitControls&&gsCamera)?new GSOrbitControls(gsCamera,gsCanvas):null;
    if(gsRenderer.setPixelRatio) gsRenderer.setPixelRatio(Math.min(1.0,devicePixelRatio));
    else if(gsRenderer.renderer?.setPixelRatio) gsRenderer.renderer.setPixelRatio(Math.min(1.0,devicePixelRatio));
  } catch(e){ console.warn('[XRVU] gsplat init:',e.message); gsScene=null; return; }
  new ResizeObserver(()=>{ if(gsRenderer?.setSize){ const w=container.clientWidth||800,h=container.clientHeight||520; gsRenderer.setSize(w,h); } }).observe(container);
  gsLoop();
}

function gsLoop(ts=0){
  requestAnimationFrame(gsLoop);
  if(!gsRenderer||!gsScene) return;
  if(ts-gsLastFrameTime<GS_MS) return;
  gsLastFrameTime=ts;
  const dt=Math.min((ts-GS_CLK.prev)/1000,0.1); GS_CLK.prev=ts;
  const wasAnimated=applyGSAnimation(dt,ts/1000);
  if(!wasAnimated) gsControls?.update();
  gsRenderer.render(gsScene,gsCamera);
}

function initGSCamera(){
  if(!gsCamera||gsCamInitialized) return;
  gsCamera.position.set(0,gsSceneRadius*0.3,gsSceneRadius*3.0);
  if(gsCamera.lookAt) gsCamera.lookAt(0,0,0);
  if(gsControls?.target?.set) gsControls.target.set(0,0,0);
  if(gsControls?.update) gsControls.update();
  gsCamInitialized=true;
}

/* ═══════════════════════════════════════════════
   LOADERS
   ═══════════════════════════════════════════════ */
let activeEngine=null;
function detectFormat(url,hint){
  if(hint&&hint!=='auto') return hint;
  const low=(url||'').toLowerCase().split('?')[0];
  if(low.endsWith('.spz'))                        return 'spz';
  if(low.endsWith('.ply'))                        return 'ply';
  if(low.endsWith('.splat'))                      return 'splat';
  if(low.endsWith('.glb')||low.endsWith('.gltf')) return 'gltf';
  if(low.endsWith('.obj'))                        return 'obj';
  if(low.endsWith('.fbx'))                        return 'fbx';
  if(low.endsWith('.stl'))                        return 'stl';
  return 'iframe';
}
async function loadModel(url,hint){
  if(!url){ const p=new URLSearchParams(location.search); if(p.has('model')) url=p.get('model'); }
  const fmt=detectFormat(url,hint);
  console.log('[XRVU] Format:',fmt,url); lbl('Chargement...'); prg(0.02);
  try {
    if(fmt==='spz')                     await loadGS_SPZ(url);
    else if(fmt==='ply'||fmt==='splat') await loadGS_Direct(url,fmt);
    else if(fmt==='gltf')               await loadThreeMesh_GLTF(url);
    else if(fmt==='obj')                await loadThreeMesh_OBJ(url);
    else if(fmt==='fbx')                await loadThreeMesh_FBX(url);
    else if(fmt==='stl')                await loadThreeMesh_STL(url);
    else                                loadIframe(url);
  } catch(e){ err(e.message||String(e)); }
}
function showEngine(type){ $('xrvu-gs-stage').style.display=type==='gs'?'block':'none'; $('xrvu-three-stage').style.display=type==='three'?'block':'none'; activeEngine=type; }

/* ─── SPZ decoder ─── */
async function loadGS_SPZ(url){
  if(!gsScene){ await initGS(); } if(!gsScene) throw new Error('gsplat indisponible');
  lbl('Telechargement SPZ...'); prg(0.05);
  const resp=await fetch(url,{mode:'cors'}); if(!resp.ok) throw new Error(`HTTP ${resp.status}`);
  const compressed=await resp.arrayBuffer(); prg(0.15);
  lbl('Decompression...'); prg(0.2);
  if(!window.DecompressionStream) throw new Error('DecompressionStream absent');
  const ds=new DecompressionStream('gzip'); const chunks=[];
  const readTask=(async()=>{ const rd=ds.readable.getReader(); for(;;){ const{done,value}=await rd.read(); if(done) break; chunks.push(value); } })();
  const wr=ds.writable.getWriter(); await wr.write(new Uint8Array(compressed)); await wr.close(); await readTask;
  const rawLen=chunks.reduce((s,c)=>s+c.length,0); const raw=new Uint8Array(rawLen);
  let off=0; for(const c of chunks){ raw.set(c,off); off+=c.length; }
  prg(0.35);
  const dv=new DataView(raw.buffer);
  const magic=dv.getUint32(0,true); if(magic!==0x5053474e) throw new Error('Magic SPZ invalide');
  const version=dv.getUint32(4,true),N=dv.getUint32(8,true);
  const shDeg=raw[12],fracBits=raw[13];
  const shDims=[0,3,8,15,24][Math.min(shDeg,4)];
  const posScale=1.0/(1<<fracBits);
  console.log('[XRVU] SPZ v'+version+' — '+N+' pts'); let p=16;
  lbl('Positions...'); prg(0.4);
  const pos=new Float32Array(N*3);
  if(version===1){ p+=N*6; }
  else { for(let i=0;i<N;i++){ for(let j=0;j<3;j++){ let v=raw[p]|(raw[p+1]<<8)|(raw[p+2]<<16); p+=3; if(v&0x800000) v|=0xFF000000; pos[i*3+j]=(v|0)*posScale; } pos[i*3+1]*=-1; pos[i*3+2]*=-1; } }
  let _normMx=1.0;
  { let sx=0,sy=0,sz=0; for(let i=0;i<N;i++){ sx+=pos[i*3]; sy+=pos[i*3+1]; sz+=pos[i*3+2]; }
    const cx=sx/N,cy=sy/N,cz=sz/N; let mx=0;
    for(let i=0;i<N;i++){ const dx=pos[i*3]-cx,dy=pos[i*3+1]-cy,dz=pos[i*3+2]-cz; mx=Math.max(mx,dx*dx+dy*dy+dz*dz); }
    mx=Math.sqrt(mx);
    for(let i=0;i<N;i++){ pos[i*3]-=cx; pos[i*3+1]-=cy; pos[i*3+2]-=cz; }
    if(mx>0.0001){ const inv=1/mx; for(let i=0;i<N;i++){ pos[i*3]*=inv; pos[i*3+1]*=inv; pos[i*3+2]*=inv; } _normMx=mx; }
    gsSceneRadius=1.0; }
  const opac=new Float32Array(N);
  for(let i=0;i<N;i++){ const a=Math.max(1e-7,Math.min(1-1e-7,raw[p++]/255)); opac[i]=Math.log(a/(1-a)); }
  const col=new Float32Array(N*3);
  for(let i=0;i<N*3;i++) col[i]=(raw[p++]/255-0.5)/0.15;
  const scl=new Float32Array(N*3);
  for(let i=0;i<N*3;i++) scl[i]=raw[p++]/16-10;
  if(_normMx>0.0001){ const logInv=-Math.log(_normMx); for(let i=0;i<N*3;i++) scl[i]+=logInv; }
  lbl('Rotations...'); prg(0.55);
  const rot=new Float32Array(N*4);
  if(version<=2){ for(let i=0;i<N;i++){ const rx=raw[p++]/127.5-1,ry=raw[p++]/127.5-1,rz=raw[p++]/127.5-1; rot[i*4]=Math.sqrt(Math.max(0,1-rx*rx-ry*ry-rz*rz)); rot[i*4+1]=rx; rot[i*4+2]=-ry; rot[i*4+3]=-rz; } }
  else { const S=Math.SQRT1_2/511; for(let i=0;i<N;i++){ const pk=dv.getUint32(p,true); p+=4; const li=pk&3; const dc=b=>((b>>9)&1?-1:1)*(b&511)*S; const a_=dc((pk>>2)&1023),b_=dc((pk>>12)&1023),c_=dc((pk>>22)&1023); const w_=Math.sqrt(Math.max(0,1-a_*a_-b_*b_-c_*c_)); const q=[0,0,0,0]; let si=0; for(let j=0;j<4;j++) q[j]=j===li?w_:[a_,b_,c_][si++]; rot[i*4]=q[0]; rot[i*4+1]=q[1]; rot[i*4+2]=-q[2]; rot[i*4+3]=-q[3]; } }
  prg(0.65);
  const sh=new Float32Array(N*shDims*3);
  for(let i=0;i<N*shDims*3;i++) sh[i]=(raw[p++]-128)/128;
  lbl('Construction PLY...'); prg(0.7);
  let hdr='ply\nformat binary_little_endian 1.0\nelement vertex '+N+'\n';
  hdr+='property float x\nproperty float y\nproperty float z\nproperty float nx\nproperty float ny\nproperty float nz\n';
  hdr+='property float f_dc_0\nproperty float f_dc_1\nproperty float f_dc_2\n';
  for(let j=0;j<shDims*3;j++) hdr+='property float f_rest_'+j+'\n';
  hdr+='property float opacity\nproperty float scale_0\nproperty float scale_1\nproperty float scale_2\n';
  hdr+='property float rot_0\nproperty float rot_1\nproperty float rot_2\nproperty float rot_3\nend_header\n';
  const nP=3+3+3+shDims*3+1+3+4;
  const hB=new TextEncoder().encode(hdr);
  const plyBuf=new ArrayBuffer(hB.length+N*nP*4); new Uint8Array(plyBuf).set(hB);
  const out=new DataView(plyBuf,hB.length); let op=0;
  for(let i=0;i<N;i++){
    out.setFloat32(op,pos[i*3],true); op+=4; out.setFloat32(op,pos[i*3+1],true); op+=4; out.setFloat32(op,pos[i*3+2],true); op+=4;
    out.setFloat32(op,0,true); op+=4; out.setFloat32(op,0,true); op+=4; out.setFloat32(op,0,true); op+=4;
    out.setFloat32(op,col[i*3],true); op+=4; out.setFloat32(op,col[i*3+1],true); op+=4; out.setFloat32(op,col[i*3+2],true); op+=4;
    for(let j=0;j<shDims*3;j++){ out.setFloat32(op,sh[i*shDims*3+j],true); op+=4; }
    out.setFloat32(op,opac[i],true); op+=4;
    out.setFloat32(op,scl[i*3],true); op+=4; out.setFloat32(op,scl[i*3+1],true); op+=4; out.setFloat32(op,scl[i*3+2],true); op+=4;
    out.setFloat32(op,rot[i*4],true); op+=4; out.setFloat32(op,rot[i*4+1],true); op+=4; out.setFloat32(op,rot[i*4+2],true); op+=4; out.setFloat32(op,rot[i*4+3],true); op+=4;
  }
  prg(0.8); lbl('Rendu 3D...');
  const plyFile=new File([plyBuf],'scene.ply',{type:'application/octet-stream'});
  showEngine('gs');
  await GSLoader.LoadFromFileAsync(plyFile,gsScene,pp=>prg(0.8+pp*0.19));
  prg(1); gsCamInitialized=false; initGSCamera();
  overlayFade(); console.log('[XRVU] GS —',N,'gaussians SPZ v'+version);
  setAnimation(CONFIG.animation.mode);
}

async function loadGS_Direct(url,fmt){
  if(!gsScene){ await initGS(); } if(!gsScene) throw new Error('gsplat indisponible');
  lbl('Telechargement '+fmt.toUpperCase()+'...'); prg(0.1);
  const resp=await fetch(url,{mode:'cors'}); if(!resp.ok) throw new Error('HTTP '+resp.status);
  const buf=await resp.arrayBuffer(); prg(0.5); lbl('Rendu 3D...');
  const file=new File([buf],'scene.'+fmt,{type:'application/octet-stream'});
  showEngine('gs');
  await GSLoader.LoadFromFileAsync(file,gsScene,pp=>prg(0.5+pp*0.49));
  prg(1); gsSceneRadius=2.0; gsCamInitialized=false; initGSCamera();
  overlayFade(); setAnimation(CONFIG.animation.mode);
}

let _baseScale=1,_baseY=0;
function showThreeMesh(mesh){
  const box=new THREE.Box3().setFromObject(mesh);
  const center=box.getCenter(new THREE.Vector3());
  const size=box.getSize(new THREE.Vector3()).length();
  mesh.position.sub(center); const nscale=2.0/(size||1); mesh.scale.setScalar(nscale);
  threeModelGroup=new THREE.Group(); threeModelGroup.add(mesh);
  threeModelGroup.position.set(CONFIG.transform.x,CONFIG.transform.y,CONFIG.transform.z);
  _baseScale=nscale*CONFIG.transform.scale; _baseY=CONFIG.transform.y;
  threeModelGroup.scale.setScalar(_baseScale); threeScene.add(threeModelGroup);
  threeCamera.position.set(0,0.5,2.5); threeControls.target.set(0,0,0); threeControls.update();
  applyMaterialConfig(mesh); showEngine('three'); prg(1); overlayFade(); setAnimation(CONFIG.animation.mode);
}
function applyMaterialConfig(obj){
  if(!obj) return;
  obj.traverse(child=>{ if(child.isMesh&&child.material){ const mats=Array.isArray(child.material)?child.material:[child.material]; mats.forEach(m=>{ if(m.roughness!==undefined) m.roughness=CONFIG.material.roughness; if(m.metalness!==undefined) m.metalness=CONFIG.material.metalness; if(m.opacity!==undefined){ m.opacity=CONFIG.material.opacity; m.transparent=CONFIG.material.opacity<1; } m.needsUpdate=true; }); } });
}
function clearThreeMesh(){ if(threeModelGroup){ threeScene.remove(threeModelGroup); threeModelGroup=null; } }
async function loadThreeMesh_GLTF(url){ lbl('Chargement GLB/GLTF...'); clearThreeMesh(); return new Promise((res,rej)=>{ new GLTFLoader().load(url,g=>{ showThreeMesh(g.scene); res(); },e=>prg((e.loaded/e.total)||0),e=>rej(e)); }); }
async function loadThreeMesh_OBJ(url){  lbl('Chargement OBJ...');      clearThreeMesh(); return new Promise((res,rej)=>{ new OBJLoader().load(url,m=>{ showThreeMesh(m); res(); },e=>prg((e.loaded/e.total)||0),e=>rej(e)); }); }
async function loadThreeMesh_FBX(url){  lbl('Chargement FBX...');      clearThreeMesh(); return new Promise((res,rej)=>{ new FBXLoader().load(url,m=>{ showThreeMesh(m); res(); },e=>prg((e.loaded/e.total)||0),e=>rej(e)); }); }
async function loadThreeMesh_STL(url){  lbl('Chargement STL...');      clearThreeMesh(); return new Promise((res,rej)=>{ new STLLoader().load(url,geo=>{ const m=new THREE.Mesh(geo,new THREE.MeshStandardMaterial({color:0xdddddd,roughness:CONFIG.material.roughness,metalness:CONFIG.material.metalness})); showThreeMesh(m); res(); },e=>prg((e.loaded/e.total)||0),e=>rej(e)); }); }
function loadIframe(url){ let src=url; if(url.includes('sketchfab.com/models')){ const id=url.split('/models/')[1]?.split('/')[0]; if(id) src='https://sketchfab.com/models/'+id+'/embed?autostart=1&ui_infos=0'; } const iframe=document.createElement('iframe'); iframe.src=src; iframe.allow='accelerometer;magnetometer;gyroscope;vr;xr-spatial-tracking;fullscreen;autoplay'; iframe.style.cssText='position:absolute;inset:0;width:100%;height:100%;border:0;z-index:10;'; $('xrvu-root').appendChild(iframe); activeEngine='iframe'; overlayFade(); }

/* ═══════════════════════════════════════════════
   MEDIA PROJECTIONS
   ═══════════════════════════════════════════════ */
let _mediaMeshes=[], _mediaVideos=[];

function buildProjectionGeo(projType,size){
  switch(projType){
    case 'sphere':   return new THREE.SphereGeometry(size,64,32);
    case 'cylinder': return new THREE.CylinderGeometry(size,size,size*0.75,64,1,true);
    case 'cube':     return new THREE.BoxGeometry(size,size,size);
    default:         return new THREE.PlaneGeometry(size,size*0.5625);
  }
}

function addVideoProjection(url,projType,size){
  if(!threeScene) return;
  const video=document.createElement('video');
  video.src=url; video.crossOrigin='anonymous'; video.loop=true; video.playsInline=true;
  const tex=new THREE.VideoTexture(video);
  const side=projType==='flat'?THREE.DoubleSide:THREE.BackSide;
  const mesh=new THREE.Mesh(buildProjectionGeo(projType,size),new THREE.MeshBasicMaterial({map:tex,side,toneMapped:false}));
  mesh.position.set(0,projType==='flat'?1.2:0,0);
  threeScene.add(mesh); _mediaMeshes.push(mesh); _mediaVideos.push(video);
  video.play().catch(()=>{ toast('Cliquez pour activer la video'); const once=()=>{ video.play().catch(()=>{}); $('xrvu-root').removeEventListener('click',once); }; $('xrvu-root').addEventListener('click',once); });
  if(activeEngine!=='three') showEngine('three');
}

function addImageProjection(url,projType,size){
  if(!threeScene) return;
  new THREE.TextureLoader().load(url,tex=>{
    tex.colorSpace=THREE.SRGBColorSpace;
    const side=projType==='flat'?THREE.DoubleSide:THREE.BackSide;
    const mesh=new THREE.Mesh(buildProjectionGeo(projType,size),new THREE.MeshBasicMaterial({map:tex,side,toneMapped:false}));
    mesh.position.set(0,projType==='flat'?1.2:0,0);
    threeScene.add(mesh); _mediaMeshes.push(mesh);
    if(activeEngine!=='three') showEngine('three');
  },undefined,()=>toast('Erreur chargement image'));
}

function clearMediaMeshes(){
  _mediaMeshes.forEach(m=>{ m.geometry.dispose(); if(m.material.map) m.material.map.dispose(); m.material.dispose(); threeScene?.remove(m); });
  _mediaMeshes=[];
  _mediaVideos.forEach(v=>{ v.pause(); v.src=''; });
  _mediaVideos=[];
}

/* ═══════════════════════════════════════════════
   VR INTERACTIONS
   ═══════════════════════════════════════════════ */
let vrControllers=[], vrTeleportRing=null, vrTeleportActive=false;
const vrTeleportPoint=new THREE.Vector3();
let vrXRRefSpace=null, vrGrabController=null, vrGrabOffset=new THREE.Matrix4();
let vrBothSqueeze=[false,false], vrInitialSqueezeDist=0, vrInitialSqueezeScale=1;
const _vrRay=new THREE.Raycaster(), _vrMat=new THREE.Matrix4();

function setupVRInteractions(){
  for(let i=0;i<2;i++){
    const ctrl=threeRenderer.xr.getController(i);
    ctrl.userData.index=i;
    ctrl.addEventListener('selectstart',()=>onVRSelectStart(i));
    ctrl.addEventListener('selectend',  ()=>onVRSelectEnd(i));
    ctrl.addEventListener('squeezestart',()=>onVRSqueezeStart(i));
    ctrl.addEventListener('squeezeend',  ()=>onVRSqueezeEnd(i));
    const ray=new THREE.Line(
      new THREE.BufferGeometry().setFromPoints([new THREE.Vector3(0,0,0),new THREE.Vector3(0,0,-1)]),
      new THREE.LineBasicMaterial({color:0x1df2d6,transparent:true,opacity:0.5})
    );
    ray.scale.z=5; ctrl.add(ray);
    threeScene.add(ctrl); vrControllers.push(ctrl);
  }
  const ringGeo=new THREE.RingGeometry(0.28,0.34,32);
  vrTeleportRing=new THREE.Mesh(ringGeo,new THREE.MeshBasicMaterial({color:0x1df2d6,side:THREE.DoubleSide,transparent:true,opacity:0.75}));
  vrTeleportRing.rotation.x=-Math.PI/2; vrTeleportRing.visible=false;
  threeScene.add(vrTeleportRing);
  threeRenderer.xr.addEventListener('sessionstart',()=>{ vrXRRefSpace=threeRenderer.xr.getReferenceSpace(); });
}

function onVRSelectStart(idx){
  const ctrl=vrControllers[idx];
  if(!ctrl) return;
  if(CONFIG.vr.handInteractions&&threeModelGroup){
    _vrMat.identity().extractRotation(ctrl.matrixWorld);
    _vrRay.ray.origin.setFromMatrixPosition(ctrl.matrixWorld);
    _vrRay.ray.direction.set(0,0,-1).applyMatrix4(_vrMat);
    if(_vrRay.intersectObject(threeModelGroup,true).length>0){
      vrGrabController=ctrl;
      vrGrabOffset.copy(ctrl.matrixWorld).invert().multiply(threeModelGroup.matrixWorld);
      return;
    }
  }
  if(CONFIG.vr.teleport&&idx===1) vrTeleportActive=true;
}

function onVRSelectEnd(idx){
  if(vrGrabController===vrControllers[idx]) vrGrabController=null;
  if(CONFIG.vr.teleport&&idx===1&&vrTeleportActive){
    vrTeleportActive=false;
    if(vrTeleportRing.visible&&vrXRRefSpace&&typeof XRRigidTransform!=='undefined'){
      const cam=threeRenderer.xr.getCamera();
      const tf=new XRRigidTransform({x:-(vrTeleportPoint.x-cam.position.x),y:0,z:-(vrTeleportPoint.z-cam.position.z),w:1});
      const newSpace=vrXRRefSpace.getOffsetReferenceSpace(tf);
      vrXRRefSpace=newSpace; threeRenderer.xr.setReferenceSpace(newSpace);
    }
    vrTeleportRing.visible=false;
  }
}

function onVRSqueezeStart(idx){
  vrBothSqueeze[idx]=true;
  if(vrBothSqueeze[0]&&vrBothSqueeze[1]&&threeModelGroup&&vrControllers.length===2){
    const p0=new THREE.Vector3().setFromMatrixPosition(vrControllers[0].matrixWorld);
    const p1=new THREE.Vector3().setFromMatrixPosition(vrControllers[1].matrixWorld);
    vrInitialSqueezeDist=p0.distanceTo(p1);
    vrInitialSqueezeScale=threeModelGroup.scale.x;
  }
}
function onVRSqueezeEnd(idx){ vrBothSqueeze[idx]=false; }

function updateVRInteractions(){
  if(vrGrabController&&threeModelGroup){
    const m=new THREE.Matrix4().copy(vrGrabController.matrixWorld).multiply(vrGrabOffset);
    m.decompose(threeModelGroup.position,threeModelGroup.quaternion,threeModelGroup.scale);
  }
  if(vrBothSqueeze[0]&&vrBothSqueeze[1]&&threeModelGroup&&!vrGrabController&&vrControllers.length===2){
    const p0=new THREE.Vector3().setFromMatrixPosition(vrControllers[0].matrixWorld);
    const p1=new THREE.Vector3().setFromMatrixPosition(vrControllers[1].matrixWorld);
    const dist=p0.distanceTo(p1);
    if(vrInitialSqueezeDist>0.001){
      const ns=Math.max(0.001,vrInitialSqueezeScale*(dist/vrInitialSqueezeDist));
      threeModelGroup.scale.setScalar(ns); syncScaleUI(ns);
    }
  }
  if(vrTeleportActive&&vrControllers[1]){
    const ctrl=vrControllers[1];
    _vrMat.identity().extractRotation(ctrl.matrixWorld);
    _vrRay.ray.origin.setFromMatrixPosition(ctrl.matrixWorld);
    _vrRay.ray.direction.set(0,0,-1).applyMatrix4(_vrMat);
    const doty=_vrRay.ray.direction.y;
    if(doty<-0.1){
      const t=-_vrRay.ray.origin.y/doty;
      if(t>0&&t<20){ vrTeleportPoint.copy(_vrRay.ray.origin).addScaledVector(_vrRay.ray.direction,t); vrTeleportRing.position.set(vrTeleportPoint.x,0.01,vrTeleportPoint.z); vrTeleportRing.visible=true; return; }
    }
    vrTeleportRing.visible=false;
  }
}

/* ═══════════════════════════════════════════════
   AR + VR BUTTONS
   ═══════════════════════════════════════════════ */
function setupXRButtons(){
  if(!threeRenderer) return;
  if(CONFIG.xr.ar&&navigator.xr) navigator.xr.isSessionSupported('immersive-ar').then(ok=>{ if(ok||/android|iphone|ipad/i.test(navigator.userAgent)) $('xrvu-btn-ar').style.display='flex'; }).catch(()=>{});
  if(CONFIG.xr.vr&&navigator.xr) navigator.xr.isSessionSupported('immersive-vr').then(ok=>{ if(ok) $('xrvu-btn-vr').style.display='flex'; }).catch(()=>{});
  $('xrvu-btn-ar').addEventListener('click',async()=>{
    if(!navigator.xr){ toast('WebXR non disponible'); return; }
    try {
      const ok=await navigator.xr.isSessionSupported('immersive-ar');
      if(!ok){ toast('AR non supporte — ouvrez depuis un telephone'); return; }
      const opts={requiredFeatures:['local-floor'],optionalFeatures:['hit-test','dom-overlay','image-tracking'],domOverlay:{root:$('xrvu-root')}};
      const itTargets=CONFIG.triggers.imageTracker.targets;
      if(itTargets.length>0){
        try {
          const bitmaps=await Promise.all(itTargets.map(t=>fetch(t.image).then(r=>r.blob()).then(b=>createImageBitmap(b))));
          opts.trackedImages=bitmaps.map((bmp,i)=>({image:bmp,widthInMeters:itTargets[i].widthInMeters||0.2}));
        } catch(e){ console.warn('[XRVU] ImageTracker:',e.message); }
      }
      xrSession=await navigator.xr.requestSession('immersive-ar',opts);
      await threeRenderer.xr.setSession(xrSession);
      const bgSave=threeScene.background; threeScene.background=null; threeRenderer.setClearColor(0x000000,0);
      $('xrvu-btn-ar').classList.add('active');
      if(CONFIG.xr.hitTest){ xrRefSpace=await xrSession.requestReferenceSpace('local-floor'); const vs=await xrSession.requestReferenceSpace('viewer'); xrHitTestSource=await xrSession.requestHitTestSource({space:vs}); $('xrvu-reticule').style.display='flex'; }
      xrSession.addEventListener('end',()=>{ threeScene.background=bgSave; applyBackground(); xrHitTestSource=null; xrRefSpace=null; $('xrvu-btn-ar').classList.remove('active'); $('xrvu-reticule').style.display='none'; });
    } catch(e){ toast('AR: '+e.message); }
  });
  const vrBtn=XRButton.createButton(threeRenderer,{mode:'immersive-vr',requiredFeatures:['local-floor'],optionalFeatures:['hand-tracking']});
  vrBtn.style.display='none'; document.body.appendChild(vrBtn);
  $('xrvu-btn-vr').addEventListener('click',async()=>{ if(!navigator.xr){ toast('WebXR non disponible'); return; } const ok=await navigator.xr.isSessionSupported('immersive-vr'); if(ok) vrBtn.click(); else toast('VR non supporte'); });
}
function updateHitTest(frame){ if(!xrHitTestSource||!xrRefSpace||!frame) return; const r=frame.getHitTestResults(xrHitTestSource); if(r.length>0&&r[0].getPose(xrRefSpace)) $('xrvu-reticule').style.display='flex'; }

/* ═══════════════════════════════════════════════
   GPS TRIGGER
   ═══════════════════════════════════════════════ */
let _gpsWatchId=null, _lastGPSTrigger=null;
function haversineDistance(lat1,lon1,lat2,lon2){ const R=6371000,dLat=(lat2-lat1)*Math.PI/180,dLon=(lon2-lon1)*Math.PI/180,a=Math.sin(dLat/2)**2+Math.cos(lat1*Math.PI/180)*Math.cos(lat2*Math.PI/180)*Math.sin(dLon/2)**2; return R*2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a)); }

function startGPSWatch(){
  if(!navigator.geolocation){ toast('GPS non disponible'); return; }
  if(_gpsWatchId!==null) return;
  _gpsWatchId=navigator.geolocation.watchPosition(pos=>{
    const{latitude:lat,longitude:lon}=pos.coords;
    $('xrvu-gps-coords').textContent=lat.toFixed(6)+', '+lon.toFixed(6);
    for(const zone of CONFIG.triggers.gps.zones){
      const dist=haversineDistance(lat,lon,zone.lat,zone.lon);
      if(dist<=(zone.radius||CONFIG.triggers.gps.radius)){
        if(_lastGPSTrigger!==zone.name){ _lastGPSTrigger=zone.name; toast('Zone GPS : '+(zone.name||'Zone')); if(zone.url) loadModel(zone.url); }
        return;
      }
    }
    _lastGPSTrigger=null;
  },e=>{ toast('GPS erreur: '+e.message); _gpsWatchId=null; },{enableHighAccuracy:true,maximumAge:3000});
  toast('GPS actif'); $('xrvu-btn-triggers').classList.add('active');
}

function addGPSZone(lat,lon,name,url,radius){
  CONFIG.triggers.gps.zones.push({lat,lon,name:name||'Zone '+(CONFIG.triggers.gps.zones.length+1),url:url||null,radius:radius||CONFIG.triggers.gps.radius});
  renderGPSZonesList();
}

function renderGPSZonesList(){
  const list=$('xrvu-gps-zones-list'); if(!list) return;
  list.innerHTML=CONFIG.triggers.gps.zones.map((z,i)=>`<div style="padding:2px 0;border-bottom:1px solid rgba(255,255,255,.05);">[${i+1}] ${z.name} — ${z.lat.toFixed(4)},${z.lon.toFixed(4)} (${z.radius||50}m) <span style="cursor:pointer;color:#e05555;" data-del="${i}">x</span></div>`).join('');
  list.querySelectorAll('[data-del]').forEach(el=>el.addEventListener('click',()=>{ CONFIG.triggers.gps.zones.splice(parseInt(el.dataset.del),1); renderGPSZonesList(); }));
}

/* ═══════════════════════════════════════════════
   GYROSCOPE + INTERACTIONS
   ═══════════════════════════════════════════════ */
let _gyroAlpha0=null,_userInteracting=false,_idleTimer=null;
function onUserInteract(){ _userInteracting=true; clearTimeout(_idleTimer); _idleTimer=setTimeout(()=>{ _userInteracting=false; },3000); }
function setupGyroscope(){
  if(!CONFIG.xr.gyroscope||!threeCamera) return;
  window.addEventListener('deviceorientation',e=>{ if(!e.gamma) return; if(_gyroAlpha0===null) _gyroAlpha0=e.alpha; if(_userInteracting) return; const alpha=THREE.MathUtils.degToRad((e.alpha||0)-_gyroAlpha0); const beta=THREE.MathUtils.degToRad(e.beta||0); const gamma=THREE.MathUtils.degToRad(e.gamma||0); threeCamera.quaternion.setFromEuler(new THREE.Euler(beta,alpha,-gamma,'YXZ')); });
}
let _pinch0=null;
$('xrvu-root').addEventListener('touchstart',e=>{ if(e.touches.length===2) _pinch0=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY); },{passive:true});
$('xrvu-root').addEventListener('touchmove',e=>{ if(e.touches.length===2&&_pinch0&&threeModelGroup){ const d=Math.hypot(e.touches[0].clientX-e.touches[1].clientX,e.touches[0].clientY-e.touches[1].clientY); const ns=Math.max(0.001,threeModelGroup.scale.x*(d/_pinch0)); threeModelGroup.scale.setScalar(ns); syncScaleUI(ns); _pinch0=d; } },{passive:true});
window.addEventListener('wheel',e=>{ if(animMode==='rotateonscroll'){ if(threeModelGroup) threeModelGroup.rotation.y+=e.deltaY*0.003; else if(gsCamera) gsAnim_angle+=e.deltaY*0.003; onUserInteract(); } },{passive:true});
$('xrvu-root').addEventListener('click',()=>{ if(animMode==='clickfade') _clickFadeDir*=-1; });

/* ═══════════════════════════════════════════════
   ANIMATIONS
   ═══════════════════════════════════════════════ */
let animMode='none',animClock=new THREE.Clock(),_clickFadeDir=1;
const _mouse=new THREE.Vector2();
window.addEventListener('mousemove',e=>{ const r=$('xrvu-root').getBoundingClientRect(); _mouse.x=((e.clientX-r.left)/r.width-0.5)*2; _mouse.y=((e.clientY-r.top)/r.height-0.5)*2; });

function setAnimation(mode){
  animMode=mode;
  document.querySelectorAll('.xrvu-anim-item').forEach(el=>el.classList.toggle('active',el.dataset.mode===mode));
  if(threeControls){ threeControls.autoRotate=(mode==='smoothorbit'); threeControls.autoRotateSpeed=CONFIG.animation.speed*2; }
  if(threeModelGroup){ _baseY=threeModelGroup.position.y; _baseScale=threeModelGroup.scale.x; }
}
function tickAnimations(dt){
  if(_userInteracting||!threeModelGroup) return;
  const s=CONFIG.animation.speed,t=animClock.getElapsedTime();
  switch(animMode){
    case 'turntable':      threeModelGroup.rotation.y+=dt*s*0.5; break;
    case 'floating':       threeModelGroup.position.y=_baseY+Math.sin(t*s*1.2)*0.08; threeModelGroup.rotation.y+=dt*s*0.12; break;
    case 'breathing':      { const p=1+Math.sin(t*s*1.5)*0.04; threeModelGroup.scale.setScalar(_baseScale*p); break; }
    case 'expandcontract': { const p=1+Math.sin(t*s)*0.18; threeModelGroup.scale.setScalar(_baseScale*p); break; }
    case 'followmouse':    threeModelGroup.rotation.y+=(_mouse.x*0.6-threeModelGroup.rotation.y)*dt*2; threeModelGroup.rotation.x+=(-_mouse.y*0.3-threeModelGroup.rotation.x)*dt*2; break;
    case 'pulsezoom':      { const d=2.5+Math.sin(t*s*0.8)*0.9; threeCamera.position.normalize().multiplyScalar(Math.max(0.5,d)); break; }
    case 'clickfade':      threeModelGroup.traverse(c=>{ if(c.isMesh&&c.material){ const ms=Array.isArray(c.material)?c.material:[c.material]; ms.forEach(m=>{ m.transparent=true; m.opacity=THREE.MathUtils.lerp(m.opacity,_clickFadeDir===1?0:1,dt*1.5); }); } }); break;
  }
}
function applyGSAnimation(dt,t){
  if(!gsCamera) return false;
  const s=CONFIG.animation.speed,r=gsSceneRadius*2.5;
  switch(animMode){
    case 'turntable':      if(_userInteracting) return false; gsAnim_angle+=dt*s*0.5; gsCamera.position.x=Math.sin(gsAnim_angle)*r; gsCamera.position.z=Math.cos(gsAnim_angle)*r; gsCamera.position.y=gsSceneRadius*0.5; if(gsCamera.lookAt) gsCamera.lookAt(0,0,0); return true;
    case 'smoothorbit':    if(_userInteracting) return false; gsAnim_angle+=dt*s*0.3; gsCamera.position.x=Math.sin(gsAnim_angle)*r; gsCamera.position.z=Math.cos(gsAnim_angle)*r; gsCamera.position.y=gsSceneRadius*0.4; if(gsCamera.lookAt) gsCamera.lookAt(0,0,0); return true;
    case 'followmouse':    if(_userInteracting){ gsControls?.update(); return false; } { const lf=Math.min(1,dt*1.8); gsCamera.position.x+=(_mouse.x*gsSceneRadius*1.5-gsCamera.position.x)*lf; gsCamera.position.y+=(gsSceneRadius*0.3-_mouse.y*gsSceneRadius*0.6-gsCamera.position.y)*lf; gsCamera.position.z=gsSceneRadius*3.0; if(gsCamera.lookAt) gsCamera.lookAt(0,0,0); } return true;
    case 'floating':       if(_userInteracting) return false; gsCamera.position.y=gsSceneRadius*0.5+Math.sin(t*s)*gsSceneRadius*0.15; return true;
    case 'pulsezoom':      if(_userInteracting) return false; gsCamera.position.z=r+Math.sin(t*s*0.8)*gsSceneRadius*0.5; return true;
    case 'rotateonscroll': gsCamera.position.x=Math.sin(gsAnim_angle)*r; gsCamera.position.z=Math.cos(gsAnim_angle)*r; gsCamera.position.y=gsSceneRadius*0.5; if(gsCamera.lookAt) gsCamera.lookAt(0,0,0); return true;
    default: return false;
  }
}

/* ═══════════════════════════════════════════════
   AUDIO
   ═══════════════════════════════════════════════ */
let audioEl=null,_soundMuted=false;
function setupMedia(){
  if(CONFIG.media.image){ const img=document.createElement('img'); img.src=CONFIG.media.image; img.style.cssText='position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:2;pointer-events:none;'; $('xrvu-root').insertBefore(img,$('xrvu-gs-stage')); }
  if(CONFIG.media.sound) initAudio(CONFIG.media.sound);
}
function initAudio(src){
  if(audioEl){ audioEl.pause(); audioEl.src=''; }
  audioEl=document.createElement('audio'); audioEl.src=src; audioEl.loop=CONFIG.media.soundLoop; audioEl.volume=0.8;
  if(CONFIG.media.soundAutoplay){ audioEl.play().catch(()=>{ toast('Cliquez pour activer le son'); const once=()=>{ audioEl?.play(); $('xrvu-root').removeEventListener('click',once); }; $('xrvu-root').addEventListener('click',once); }); }
  const btn=$('xrvu-btn-sound'); btn.style.display='flex';
  if(CONFIG.media.soundAutoplay) btn.classList.add('active');
  btn.onclick=e=>{ e.stopPropagation(); _soundMuted=!_soundMuted; audioEl.muted=_soundMuted; if(_soundMuted){ audioEl.pause(); btn.classList.remove('active'); btn.innerHTML=ICONS.volumeOff; } else { audioEl.play().catch(()=>{}); btn.classList.add('active'); btn.innerHTML=ICONS.volumeOn; } };
}

/* ═══════════════════════════════════════════════
   PANNEAUX UI
   ═══════════════════════════════════════════════ */
let _proportionalLock=true;

function syncScaleUI(actualScale){
  const sl=$('xrvu-tscale'),nm=$('xrvu-tscale-num');
  if(sl) sl.value=Math.max(-2,Math.min(3,Math.log10(Math.max(0.0001,actualScale))));
  if(nm) nm.value=actualScale.toFixed(4);
}
function applyScale(actualScale){
  actualScale=Math.max(0.0001,actualScale);
  if(threeModelGroup) threeModelGroup.scale.setScalar(actualScale);
  if(activeEngine==='gs') gsSceneRadius=actualScale;
  syncScaleUI(actualScale);
}

function setupTransformPanel(){
  const mkSl=(id,vid,cb)=>{ const s=$(id),v=$(vid); if(!s) return; s.addEventListener('input',()=>{ v.textContent=parseFloat(s.value).toFixed(2); cb(parseFloat(s.value)); }); };
  mkSl('xrvu-tx','xrvu-tx-val',val=>{ if(threeModelGroup) threeModelGroup.position.x=val; });
  mkSl('xrvu-ty','xrvu-ty-val',val=>{ if(threeModelGroup) threeModelGroup.position.y=_baseY+val; });
  mkSl('xrvu-tz','xrvu-tz-val',val=>{ if(threeModelGroup) threeModelGroup.position.z=val; });
  const scaleSl=$('xrvu-tscale'),scaleNum=$('xrvu-tscale-num');
  if(scaleSl) scaleSl.addEventListener('input',()=>{ const actual=Math.pow(10,parseFloat(scaleSl.value)); scaleNum.value=actual.toFixed(4); applyScale(actual); });
  if(scaleNum) scaleNum.addEventListener('change',()=>{ const v=parseFloat(scaleNum.value); if(!isNaN(v)&&v>0) applyScale(v); });
  const lb=$('xrvu-lock-btn');
  lb.addEventListener('click',e=>{ e.stopPropagation(); _proportionalLock=!_proportionalLock; lb.classList.toggle('locked',_proportionalLock); lb.innerHTML=_proportionalLock?ICONS.lock:ICONS.lockOpen; });
}

function setupSettingsPanel(){
  const mkSl=(id,vid,cb)=>{ const s=$(id),v=$(vid); if(!s) return; s.addEventListener('input',()=>{ v.textContent=parseFloat(s.value).toFixed(2); cb(parseFloat(s.value)); }); };
  mkSl('xrvu-s-ambient','xrvu-s-ambient-val',v=>{ if(ambientLight) ambientLight.intensity=v; });
  mkSl('xrvu-s-light','xrvu-s-light-val',v=>{ if(keyLight) keyLight.intensity=v; });
  mkSl('xrvu-s-opacity','xrvu-s-opacity-val',v=>{ CONFIG.material.opacity=v; if(threeModelGroup) applyMaterialConfig(threeModelGroup); });
  mkSl('xrvu-s-roughness','xrvu-s-roughness-val',v=>{ CONFIG.material.roughness=v; if(threeModelGroup) applyMaterialConfig(threeModelGroup); });
  mkSl('xrvu-s-metalness','xrvu-s-metalness-val',v=>{ CONFIG.material.metalness=v; if(threeModelGroup) applyMaterialConfig(threeModelGroup); });
}

function setupMediaPanel(){
  let videoProj='flat',imageProj='flat';
  function initProjBtns(groupId,onSelect){
    document.querySelectorAll('#'+groupId+' .xrvu-proj-btn').forEach(btn=>{
      btn.addEventListener('click',()=>{ document.querySelectorAll('#'+groupId+' .xrvu-proj-btn').forEach(b=>b.classList.remove('active')); btn.classList.add('active'); onSelect(btn.dataset.proj); });
    });
  }
  initProjBtns('xrvu-mv-proj',p=>videoProj=p);
  initProjBtns('xrvu-mi-proj',p=>imageProj=p);
  const mvSz=$('xrvu-mv-size'),mvSzV=$('xrvu-mv-size-val'); if(mvSz) mvSz.addEventListener('input',()=>mvSzV.textContent=parseFloat(mvSz.value).toFixed(1));
  const miSz=$('xrvu-mi-size'),miSzV=$('xrvu-mi-size-val'); if(miSz) miSz.addEventListener('input',()=>miSzV.textContent=parseFloat(miSz.value).toFixed(1));
  const maVol=$('xrvu-ma-vol'),maVolV=$('xrvu-ma-vol-val'); if(maVol) maVol.addEventListener('input',()=>{ maVolV.textContent=parseFloat(maVol.value).toFixed(2); if(audioEl) audioEl.volume=parseFloat(maVol.value); });
  $('xrvu-mv-apply').addEventListener('click',()=>{ const url=$('xrvu-mv-url').value.trim(); if(!url){ toast('Entrez une URL video'); return; } if(!threeScene) initThree(); addVideoProjection(url,videoProj,parseFloat($('xrvu-mv-size').value)); $('xrvu-mv-remove').style.display='block'; toast('Video chargee'); });
  $('xrvu-mv-remove').addEventListener('click',()=>{ clearMediaMeshes(); $('xrvu-mv-remove').style.display='none'; toast('Video retiree'); });
  $('xrvu-mi-apply').addEventListener('click',()=>{ const url=$('xrvu-mi-url').value.trim(); if(!url){ toast('Entrez une URL image'); return; } if(!threeScene) initThree(); addImageProjection(url,imageProj,parseFloat($('xrvu-mi-size').value)); $('xrvu-mi-remove').style.display='block'; toast('Image chargee'); });
  $('xrvu-mi-remove').addEventListener('click',()=>{ clearMediaMeshes(); $('xrvu-mi-remove').style.display='none'; toast('Image retiree'); });
  $('xrvu-ma-apply').addEventListener('click',()=>{ const url=$('xrvu-ma-url').value.trim(); if(!url){ toast('Entrez une URL audio'); return; } CONFIG.media.sound=url; CONFIG.media.soundAutoplay=true; initAudio(url); toast('Audio charge'); });
}

function setupTriggersPanel(){
  const gpsR=$('xrvu-gps-radius'),gpsRV=$('xrvu-gps-radius-val'); if(gpsR) gpsR.addEventListener('input',()=>{ gpsRV.textContent=gpsR.value; CONFIG.triggers.gps.radius=parseInt(gpsR.value); });
  $('xrvu-gps-watch').addEventListener('click',startGPSWatch);
  $('xrvu-gps-add').addEventListener('click',()=>{
    if(!navigator.geolocation){ toast('GPS indisponible'); return; }
    navigator.geolocation.getCurrentPosition(pos=>{ const name=$('xrvu-gps-zone-name').value.trim(),url=$('xrvu-gps-zone-url').value.trim(); addGPSZone(pos.coords.latitude,pos.coords.longitude,name,url,CONFIG.triggers.gps.radius); toast('Zone GPS ajoutee : '+(name||'Zone')); });
  });
  const itW=$('xrvu-it-width'),itWV=$('xrvu-it-width-val'); if(itW) itW.addEventListener('input',()=>itWV.textContent=parseFloat(itW.value).toFixed(2));
  $('xrvu-it-add').addEventListener('click',()=>{
    const imgUrl=$('xrvu-it-url').value.trim(),contentUrl=$('xrvu-it-content').value.trim();
    if(!imgUrl){ toast('Entrez une URL image cible'); return; }
    const w=parseFloat($('xrvu-it-width').value);
    CONFIG.triggers.imageTracker.targets.push({image:imgUrl,widthInMeters:w,contentUrl:contentUrl||null});
    toast('Tracker image ajoute');
    const list=$('xrvu-it-list'); if(list) list.innerHTML+=`<div style="padding:2px 0;">${imgUrl.split('/').pop()} (${w}m)</div>`;
  });
}

/* ═══════════════════════════════════════════════
   INIT UI
   ═══════════════════════════════════════════════ */
function initUI(){
  $('xrvu-bar').style.display=CONFIG.commands.display?'flex':'none';
  applyBackground();
  if(CONFIG.overlay.logo||CONFIG.overlay.title){ const br=$('xrvu-brand'); br.style.display='flex'; if(CONFIG.overlay.logo) $('xrvu-brand-logo').src=CONFIG.overlay.logo; if(CONFIG.overlay.title){ $('xrvu-brand-title').textContent=CONFIG.overlay.title; $('xrvu-brand-title').style.color=CONFIG.overlay.titleColor; } }
  const sync=(id,vid,v)=>{ const el=$(id); if(!el) return; el.value=v; const vel=$(vid); if(vel) vel.textContent=parseFloat(v).toFixed(2); };
  sync('xrvu-tx','xrvu-tx-val',CONFIG.transform.x); sync('xrvu-ty','xrvu-ty-val',CONFIG.transform.y); sync('xrvu-tz','xrvu-tz-val',CONFIG.transform.z);
  $('xrvu-tscale').value=Math.log10(Math.max(0.0001,CONFIG.transform.scale));
  $('xrvu-tscale-num').value=(CONFIG.transform.scale||1).toFixed(4);
  sync('xrvu-s-ambient','xrvu-s-ambient-val',CONFIG.lights.ambient); sync('xrvu-s-light','xrvu-s-light-val',CONFIG.lights.directional);
  sync('xrvu-s-opacity','xrvu-s-opacity-val',CONFIG.material.opacity); sync('xrvu-s-roughness','xrvu-s-roughness-val',CONFIG.material.roughness); sync('xrvu-s-metalness','xrvu-s-metalness-val',CONFIG.material.metalness);
  const animBtn=$('xrvu-btn-anim'),animMenu=$('xrvu-anim-menu'); let _menuOpen=false;
  const openM=()=>{ animMenu.classList.add('open'); _menuOpen=true; animBtn.classList.add('active'); };
  const closeM=()=>{ animMenu.classList.remove('open'); _menuOpen=false; animBtn.classList.remove('active'); };
  animBtn.addEventListener('click',e=>{ e.stopPropagation(); _menuOpen?closeM():openM(); });
  animMenu.addEventListener('click',e=>{ const item=e.target.closest('.xrvu-anim-item'); if(!item) return; setAnimation(item.dataset.mode); closeM(); });
  document.addEventListener('click',e=>{ if(!$('xrvu-root').contains(e.target)||(!animBtn.contains(e.target)&&!animMenu.contains(e.target))) closeM(); });
  const allPanelIds=['xrvu-panel-transform','xrvu-panel-settings','xrvu-panel-media','xrvu-panel-triggers'];
  const allBtnIds=['xrvu-btn-transform','xrvu-btn-settings','xrvu-btn-media','xrvu-btn-triggers'];
  function closeAllPanels(){ allPanelIds.forEach(id=>$(id)?.classList.remove('open')); allBtnIds.forEach(id=>$(id)?.classList.remove('active')); }
  function togglePanel(pId,bId){ const open=!$(pId).classList.contains('open'); closeAllPanels(); $(pId).classList.toggle('open',open); $(bId).classList.toggle('active',open); }
  $('xrvu-btn-transform').addEventListener('click',e=>{ e.stopPropagation(); togglePanel('xrvu-panel-transform','xrvu-btn-transform'); });
  $('xrvu-btn-settings').addEventListener('click',e=>{ e.stopPropagation(); togglePanel('xrvu-panel-settings','xrvu-btn-settings'); });
  $('xrvu-btn-media').addEventListener('click',e=>{ e.stopPropagation(); togglePanel('xrvu-panel-media','xrvu-btn-media'); });
  $('xrvu-btn-triggers').addEventListener('click',e=>{ e.stopPropagation(); togglePanel('xrvu-panel-triggers','xrvu-btn-triggers'); });
  $('xrvu-root').addEventListener('click',closeAllPanels);
  allPanelIds.forEach(id=>$(id)?.addEventListener('click',e=>e.stopPropagation()));
  $('xrvu-btn-qr').addEventListener('click',()=>{ const panel=$('xrvu-qr-panel'); const visible=panel.style.display==='block'; if(visible){ panel.style.display='none'; $('xrvu-btn-qr').classList.remove('active'); return; } panel.style.display='block'; $('xrvu-btn-qr').classList.add('active'); $('xrvu-qr-code').innerHTML=''; const url=CONFIG.model.url?location.href.split('?')[0]+'?model='+encodeURIComponent(CONFIG.model.url):location.href; if(window.QRCode) new window.QRCode($('xrvu-qr-code'),{text:url,width:120,height:120,colorDark:'#0010ef',colorLight:'#ffffff',correctLevel:window.QRCode.CorrectLevel.H}); });
  $('xrvu-btn-fs').addEventListener('click',()=>{ const el=$('xrvu-root'); if(!document.fullscreenElement) el.requestFullscreen?.(); else document.exitFullscreen?.(); });
  document.addEventListener('fullscreenchange',()=>{ $('xrvu-btn-fs').innerHTML=document.fullscreenElement?ICONS.compress:ICONS.expand; });
  $('xrvu-root').addEventListener('dblclick',()=>{ threeControls?.reset(); if(threeCamera) threeCamera.position.set(0,0.5,2.5); if(gsCamera){ gsCamera.position.set(0,gsSceneRadius*0.3,gsSceneRadius*3.0); if(gsCamera.lookAt) gsCamera.lookAt(0,0,0); gsCamInitialized=true; } });
  const params=new URLSearchParams(location.search); if(params.has('model')) CONFIG.model.url=params.get('model');
  setupTransformPanel(); setupSettingsPanel(); setupMediaPanel(); setupTriggersPanel();
  if(CONFIG.hud.autoHide) _hudTimer=setTimeout(()=>$('xrvu-bar').classList.add('hud-hidden'),CONFIG.hud.autoHideDelay*2);
}

/* ═══════════════════════════════════════════════
   BOUCLE + INIT
   ═══════════════════════════════════════════════ */
function threeLoop(t,frame){
  if(frame&&CONFIG.xr.hitTest) updateHitTest(frame);
  if(threeRenderer.xr.isPresenting) updateVRInteractions();
  tickAnimations(animClock.getDelta());
  threeControls?.update();
  threeRenderer.render(threeScene,threeCamera);
}

async function init(){
  try {
    initThree(); initUI(); setupGyroscope(); setupMedia();
    if(CONFIG.triggers.gps.enabled&&CONFIG.triggers.gps.zones.length) startGPSWatch();
    if(CONFIG.model.url){
      const fmt=detectFormat(CONFIG.model.url,CONFIG.model.format);
      if(fmt==='spz'||fmt==='ply'||fmt==='splat') initGS().then(()=>loadModel(CONFIG.model.url,CONFIG.model.format)).catch(e=>err('GS: '+(e.message||e)));
      else { loadModel(CONFIG.model.url,CONFIG.model.format); initGS(); }
    } else { lbl('Aucun modele configure'); initGS(); }
  } catch(e){ err('Init: '+(e.message||String(e))); }
}
init();
</script>
				</div>
				</div>
				</div>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/spz/">spz</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Paper plane</title>
		<link>https://presentcomposedesign.fr/paper-plane-mode_for_arrival-space/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 27 Mar 2026 01:19:08 +0000</pubDate>
				<category><![CDATA[[ia]]]></category>
		<category><![CDATA[[VR]]]></category>
		<category><![CDATA[Design d'espace]]></category>
		<category><![CDATA[Design produit]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=36135</guid>

					<description><![CDATA[<p>Click here &#x1F861; from your VR headset Paper Plane in VR ᯅ Plein écran &#x1F5D6; Paper Plane Mon tout premier plugin Arrival.Space. Un avatar universel pour le web immersif. Le concept Paper Plane est parti d&#8217;une question simple : et si le meilleur avatar était aussi le plus universel ? Pas de personnage genré, pas de corps humanoïde. Juste un avion en papier, instinctif et léger, qui traverse librement chaque monde d&#8217;Arrival.Space. Pourquoi un avion en papier ? Tout le monde en a plié un. Tout le monde en a lancé un. C&#8217;est peut-être l&#8217;objet le plus démocratique qui existe. En tant qu&#8217;avatar, il efface toute friction d&#8217;identification : pas d&#8217;âge, pas de genre, pas de skin à choisir. Du mouvement pur, et une liberté totale d&#8217;exploration. De SplatGate à Paper Plane Ce projet s&#8217;appuie sur toute l&#8217;expertise en Gaussian Splatting que j&#8217;ai construite avec SplatGate. Paper Plane, c&#8217;est mon premier pas dans l&#8217;écosystème Arrival.Space, un nouveau terrain pour pousser les limites du web immersif, du spatial computing et du vibe coding. 🧊 Gaussian Splatting 🌐 Web Immersif Full VR available Experience -ᯅ- ✔️ Explorer les univers gagnants Essayer Paper Plane Soutenir / Remercier Organisé par Arrival.Space &#038; CHOICE DAO</p>
<p>Cet article <a href="https://presentcomposedesign.fr/paper-plane-mode_for_arrival-space/">Paper plane</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="36135" class="elementor elementor-36135">
						<header class="elementor-section elementor-top-section elementor-element elementor-element-f1e5d23 elementor-section-full_width elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="f1e5d23" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-no">
					<header class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-8a6a45b" data-id="8a6a45b" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-035d3b0 elementor-widget__width-inherit elementor-widget elementor-widget-html" data-id="035d3b0" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!--
// PAPER PLANE MODE for Arrival space, © All rights reserved.
//
//                                                                              ++==--=+++-=
//                                                                     +++++-:::::-=++=:. .=
//                                                        +++++=++============++*+=:....  .=
//                                              =+++++===================+**#*=-:::.... .:-=
//                                 =+++++++++===========++++**********###*==-::::::..:-====
//                          %%%##********************************##%%%#**+==-::::-=========
//                     **************************************#%%%%%*+**++++==--=+++++++++=-
//               **************************************###%%%%##*************#*++++++++++=
//            ****************########################%%%%%**************######*+++++++++=
//                 ####***#######################%%%%%##*************############*+++++++
//                       ####################%%%%%##**************#################*++++=
//                              @#######%%%%%%%***************######################***+-
//                                   @%%%%##**************############################*+
//                                    %%%###########**#################################*
//                                    %%%#########*####################################
//                                    @%%%####**-     @%#%###########################
//                                    @%%%#+                 %%##################%
//                                                                %%%%%%%%%%%%#%
//                                                                    @%%%%%%@
//
// Dev-Xprmnts · VR_Xprmnts, Present Compound Design           ║
// ║ Alban DESBARAX - Designer 360° / Creative Technologist    ║
// ║ Toulouse, FRANCE                                          ║
// ║                                                           ║
// ║   · Expertise & Support 2D, 3D, AR, VR, XR, AI            ║
// ║   · Product Design & Industrial Design                    ║
// ║   · Digital communication                                 ║
// ║   · Immersive experiences  -ᯅ- ✔️                       ║
// ║                                                           ║
// · 🡺 https://presentcomposedesign.fr/
//
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#*++==------===**%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++-::::::::::::::::::::::-=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@#+::::::::::::::::::::::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@%+:::::::::::::::::=++***+=-::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@#=::::::::::::::::+%@@@@@@@@@@%+-:::::::::::::::::::=#@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@#-::::::::::::::::#@@@@@@@@@@@@@@@@%-:::::::::::::::::::=#@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@%=::::::::::::::::*@@@@@@**==-=+##@@@@@*-:::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@=:::::::::::::::::%@@@@@+::::::::::-*@@@@#-::::::::::::::::::::=@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@#::::::::::::::::::%@@@@=::::::::::::::-%@@@#-:::::::::::::::::::::#@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@=::::::::::::::::::*@@@@=::::::::::::::::-%@@@*::::::::::::::::::::::=@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@%-::::::::::::::::::-@@@@=::::::::::::::::::-%@@@-::::::::::::::::::::::-%@@@@@@@@@@@@@
// @@@@@@@@@@@@#::::::::::::::::::::*@@@#::::::::::::::::::::=@@@*::::::::::::::::::::::::*@@@@@@@@@@@@
// @@@@@@@@@@@#:::::::::::::::::::::%@@@+::::::::::::::::::::-@@@%:::::::::::::::::::::::::*@@@@@@@@@@@
// @@@@@@@@@@+::::::::::::::::::::::@@@@-:::::::::::::::::::::%@@@::::::::::::::::::::::::::*@@@@@@@@@@
// @@@@@@@@@*:::::::::::::::::::::::@@@@=:::::::::::::::::::::@@@@:::::::::::::::::::::::::::*@@@@@@@@@
// @@@@@@@@%::::::::::::::::::::::::@@@@*:::::::::::::::::::::@@@%::::::::::::::::::::::::::::*@@@@@@@@
// @@@@@@@%:::::::::::::::::::::::::@@@@%::::::::::::::::::::+@@@*:::::::::::::::::::::::::::::%@@@@@@@
// @@@@@@@::::::::::::::::::::::::::@@@@@*::::::::::::::::::-@@@@::::::::::::::::::::::::::::::-@@@@@@@
// @@@@@@=::::::::::::::::::::::::::@@@@@@*::::::::::::::::-@@@@+:::::::::::::::::::::::::::::::*@@@@@@
// @@@@@%:::::::::::::::::::::::::::@@@@@@@*::::::::::::::-%@@@#:::::::::::::::::::::::::::::::::*@@@@@
// @@@@@::::::::::::::::::::::::::::@@@@@@@@@*::::::::::+@@@@@*::::::::::::::::::::::::::::::::::-@@@@@
// @@@@*::::::::::::::::::::::::::::@@@#=@@@@@@%#*+=**%@@@@@@=::::::::::::::::::::::::::::::::::::*@@@@
// @@@@:::::::::::::::::::::::::::::@@@#::*@@@@@@@@@@@@@@@@*:::::::::::::::::::::::::::::::::::::::@@@@
// @@@*:::::::::::::::::::::::::::::@@@#::::=*@@@@@@@@@%#=:::::::::::::::::::::::::::::::::::::::::#@@@
// @@@=:::::::::::::::::::::::::::::@@@#::::::::-==+=-:::::::::::::::::::::::::::::::::::::::::::::=@@@
// @@@::::::::::::::::::::::::::::::@@@#:::::::::::::::::::::::::::::::::::::::::::::::::--:::::::::@@@
// @@*::::::::::::::::::::::::::::::@@@#:::::::::+######*:::::::::::::::::::::::::::::::+@=:::::::::#@@
// @@*::::::::::::::::::::::::::::::@@@#:::--::::===+*+==:::::=-:::::::=-::::::-::::::::+@=:::::::::+@@
// @@:::::::::::::::::::::::::::::::@@@#::+@#@@::-#@@%@%=::=@@@@+:::+@@@@@+-::@@@@%*-::#@@%#:::::::::@@
// @@:::::::::::::::::+*##%%#*=-::::@@@#::+@@=::-%@:::-*@=:%@-:=:::*@*:::-@*::@@-:=@%::=*@*=:::::::::@@
// @@::::::::::::::+%@@@@@@@@@@@%*-:@@@#::+@*:::*@@@@@@@@#:+@%*-:::@@@@@@@@@-:@%:::#@:::+@=::::::::::@@
// @%::::::::::::*@@@@@@@@@@@@@@@@@#+@@#::+@+:::+@=-------:::=%@*::@%-------::@%:::#@:::+@=::::::::::%@
// @%::::::::::-@@@@@@++-::::-=#@@@@@+*#::+@+:::-@%=-:+%%-:-=::#@::*@*-::+%=::@%:::#@:::+@=::::::::::#@
// @%:::::::::=@@@@%+::::::::::::#@@@@**::+@+::::-#@@@@%=::#@%%@+:::+@@@@@*:::@%:::#@:::+@=::::::::::%@
// @%::::::::-@@@@+:::::::::::::::-@@@@+:::-::::::::--:::::::=-:::::::-=-:::::--:::-=----=-::::::::::%@
// @@:::::::-@@@@*:::::::::::::::::-%%%*:::::::::::::::::::::::::::::::::::::::::::+%%%%%%#::::::::::@@
// @@:::::::*@@@#:::::::+#@%*-::::::=+*#*=+#*=-:::::+#%%#-::::::=#%%#=::::-#@@#-::::=##%#+-::::::::::@@
// @@-::::::@@@@-:::::-%@#+*%@*:::::%@#+#@@+*@*::::%@+==#@*::::%@#+=%@*-::%@-=*=:::*@*+=+@%-::::::::-@@
// @@+:::::-@@@@::::::#@=::::#@=::::%@::=@*::#@-::*@=::::-@+::*@*::::*@*::*@*-::::-@@####%@#::::::::*@@
// @@#:::::-@@@*::::::@@:::::=@*::::%@::=@*::#@-::%@::::::@*::%@-::::-@%:::=%@%-::*@#******+::::::::*@@
// @@@-::::-@@@%::::::#@+::::%@-::::%@::=@*::#@-::@@-::::=@-::*@*::::*@*:::-::@%::=@*::::-=-::::::::@@@
// @@@+:::::@@@@-::::::%@%*#@@+:::::%@::=@*::#@-::@@@#=+#@+::::*@%*+@@*:::#@*+@*:::*@%*+%@%::::::::-@@@
// @@@#:::::#@@@+:::::::=*##+-::::::+*::-*=::+*:::@%=*%#*-::::::=*%#*-:::::=*#+:::::-*##*=--=::::::*@@@
// @@@@-::::=@@@@-::::::::::::::::::=**+::::::::::@%:::::::::::::::::::::::-==++**##%%@@@@@@@-::::-@@@@
// @@@@*:::::*@@@@-::::::::::::::::+@@@#::::::::::::::::::::-==++**##=-#@@@@@@@@@@@@@@@@@@@@@=::::*@@@@
// @@@@@-:::::#@@@@+-:::::::::::::*@@@@::::::-==++--##%@@@@@@@@@#*#@@%%@@@@@@@@@@@#@@@@@*#@@@+:::-@@@@@
// @@@@@%::::::*@@@@@+-:::::::::+@@@@%:=@@@@@@@@@@==@@@**%@@@@*-#@*-@@*@@@*-+**@@@:%@@==@++@@*:::%@@@@@
// @@@@@@*::::::=@@@@@@@%%**##@@@@@@=::=@@@@#-:--=-=@@=+@+=@@@:%@@@=+@-*@*-@@@+:@@=#@:*@@%-@@#::+@@@@@@
// @@@@@@@-:::::::+%@@@@@@@@@@@@@@#-::::@@@+-%@@@*--@@:@@=*@@@%=*%@@@@*=@-*@@@*:+@=+=#@@@%:@@%:-@@@@@@@
// @@@@@@@@-::::::::=*%@@@@@@@##-:::::::@@@:#@@@@@*:@@:%==@@@@@@%+-%@@#-@*+@@@:+:@*:*@@@@@:%@@-@@@@@@@@
// @@@@@@@@#-:::::::::::::-:::::::::::::@@%:%@@@@@*-@@-#@@@#-@*%@@@-#@@:@@#=+:%@-#@:@@@@@@*=@@%@@@@@@@@
// @@@@@@@@@*:::::::::::::::::::::::::::#@@--@@@@%:*@@%*+*=*@@=+@@@=+@@-#@@@@@@@=#@#@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@*-:::::::::::::::::::::::::#@@@+-==-:#@@@@@@@@@@@@#++*#@@@@@@@#@@@%:@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@*-::::::::::::::::::::::::+@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@-=-:+**++==--::%@@@@@@@@@@@
// @@@@@@@@@@@@#-:::::::::::::::::::::::=@@@@@@@@@@@@@@@@@@@@@%%##**++=---::::::::::::::::%@@@@@@@@@@@@
// @@@@@@@@@@@@@@-::::::::::::::::::::::-@@@@@@%###**++=--::::::::::::::::::::::::::::::-%@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@+::::::::::::::::::::::--::::::::::::::::::::::::::::::::::::::::::::+@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@%-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-%@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@+-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@%=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@%=::::::::::::::::::::::::::::::::::::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@%=-:::::::::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@*-:::::::::::::::::::::::::::::::::::::::::::::#@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@%+-:::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*=-:::::::::::::::::::::::::::::::+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%**=-:::::::::::::::::::::=+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%**++=====+++*##@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 
-->
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div class="paperplane-container">
    <iframe
        id="arrival-space-iframe-pp"
        src="https://arrival.space/82998375_8446?utm=embed_82998375"
        width="100%"
        height="860"
        allow="camera; microphone; vr; xr; xr-spatial-tracking; fullscreen"
        allowfullscreen
        loading="lazy">
    </iframe>
    <div class="pp-buttons-container">
        <div class="pp-vr-instruction-text">
            Click here &#x1F861; from your VR headset
        </div>
        <a
            href="https://arrival.space/82998375_8446"
            target="_blank"
            class="pp-direct-link pp-vr-button"
        >
            <i class="fa-regular fa-paper-plane"></i> Paper Plane in VR ᯅ
        </a>
        <a
            id="pp-fullscreen-link"
            class="pp-direct-link pp-fullscreen-button"
        >
            Plein écran &#x1F5D6;
        </a>
    </div>
</div>
<style>
    .paperplane-container {
        position: relative;
        width: 100vw;
        max-width: 100%;
        margin: 0;
        padding: 0;
        height: 860px;
        overflow: hidden;
    }
    .pp-buttons-container {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        pointer-events: none;
    }
    .pp-vr-instruction-text {
        position: absolute;
        top: 64px;
        left: 50%;
        transform: translateX(-50%);
        color: white;
        font-size: 14px;
        text-align: center;
        z-index: 1001;
        text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
        pointer-events: auto;
    }
    .pp-direct-link {
        position: absolute;
        padding: 8px 15px;
        background: #00BFFF;
        color: white;
        text-decoration: none;
        font-weight: bold;
        font-size: 14px;
        border-radius: 8px;
        border: 2px solid white;
        box-shadow: 0 0 8px rgba(0, 191, 255, 0.7);
        z-index: 1000;
        pointer-events: auto;
        cursor: pointer;
        transition: all 0.3s;
        font-family: sans-serif;
    }
    .pp-vr-button {
        top: 16px;
        left: 50%;
        transform: translateX(-50%);
    }
    .pp-fullscreen-button {
        bottom: 20px;
        right: 20px;
    }
    .pp-direct-link:hover {
        background: #1E90FF;
        box-shadow: 0 0 12px rgba(0, 191, 255, 0.9);
        z-index: 1001 !important;
    }
    #arrival-space-iframe-pp {
        border: none;
        display: block;
        width: 100vw;
        margin: 0;
    }
</style>
<script>
    document.getElementById('pp-fullscreen-link').addEventListener('click', function(e) {
        e.preventDefault();
        var iframe = document.getElementById('arrival-space-iframe-pp');
        if (iframe.requestFullscreen) iframe.requestFullscreen();
        else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen();
        else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen();
    });
</script>
				</div>
				</div>
					</div>
		</header>
					</div>
		</header>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-a5e22ff elementor-section-full_width elementor-section-stretched elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="a5e22ff" data-element_type="section" data-e-type="section" data-settings="{&quot;stretch_section&quot;:&quot;section-stretched&quot;,&quot;background_background&quot;:&quot;classic&quot;}">
						<div class="elementor-container elementor-column-gap-default">
					<header class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-8d89f52" data-id="8d89f52" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-2954048 elementor-widget__width-inherit elementor-widget elementor-widget-html" data-id="2954048" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!--
// PAPER PLANE MODE for Arrival space, © All rights reserved.
//
//                                                                              ++==--=+++-=
//                                                                     +++++-:::::-=++=:. .=
//                                                        +++++=++============++*+=:....  .=
//                                              =+++++===================+**#*=-:::.... .:-=
//                                 =+++++++++===========++++**********###*==-::::::..:-====
//                          %%%##********************************##%%%#**+==-::::-=========
//                     **************************************#%%%%%*+**++++==--=+++++++++=-
//               **************************************###%%%%##*************#*++++++++++=
//            ****************########################%%%%%**************######*+++++++++=
//                 ####***#######################%%%%%##*************############*+++++++
//                       ####################%%%%%##**************#################*++++=
//                              @#######%%%%%%%***************######################***+-
//                                   @%%%%##**************############################*+
//                                    %%%###########**#################################*
//                                    %%%#########*####################################
//                                    @%%%####**-     @%#%###########################
//                                    @%%%#+                 %%##################%
//                                                                %%%%%%%%%%%%#%
//                                                                    @%%%%%%@
//
// Dev-Xprmnts · VR_Xprmnts, Present Compound Design           ║
// ║ Alban DESBARAX - Designer 360° / Creative Technologist    ║
// ║ Toulouse, FRANCE                                          ║
// ║                                                           ║
// ║   · Expertise & Support 2D, 3D, AR, VR, XR, AI            ║
// ║   · Product Design & Industrial Design                    ║
// ║   · Digital communication                                 ║
// ║   · Immersive experiences  -ᯅ- ✔️                       ║
// ║                                                           ║
// · 🡺 https://presentcomposedesign.fr/
//
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#****+++++****##%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+-::::::::::::::::::::==*#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+-::::::::::::::::::::::::::::::==#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-::::::::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@*-::::::::::::::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@#+:::::::::::::::++****%%@@@@@%%##**=--:::::::::::::=#@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@*=:::::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@#*=-:::::::::::=#@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@#=:::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#=-::::::::::=#@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@%=::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*=::::::::::=%@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@*::::::::::*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-:::::::::*%@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@%=::::::::=*@@@@@@@@@@@@@@%#*********#%%@@@@@@@@@@@@@@@@@@@%+-::::::::=%@@@@@@@@@@@@@@
// @@@@@@@@@@@@@#:::::::::#@@@@@@@@@@@**+-::::::::::::::::-+#%@%@@@@@@@@@@@@@@%+-::::::::*@@@@@@@@@@@@@
// @@@@@@@@@@@@+::::::::+@@@@@@@@@@*-::::::::::::::::::::::#@@@##%%@@@@@@@@@@@@@@+::::::::*%@@@@@@@@@@@
// @@@@@@@@@@@=:::::::=#@@@@@@@@@+::::::::::::::::::::::::-*@@@@@@#%%@@@@@@@@@@@@@*-:::::::=%@@@@@@@@@@
// @@@@@@@@@@=:::::::*@@@@@@@@@%=::::::::::::::::::::::::::*@@@@@@@@##%@@@@@@@@@@@@%+:::::::=%@@@@@@@@@
// @@@@@@@@@%=:::::::#@@@@@@@@@%:::::::::::::::::::::::::::+@@@@@@@@@@@%%@@@@@@@@@@@@@*-::::::-%@@@@@@@
// @@@@@@@@@=::::::-#@@@@@@@@@%-:::::::::::::::::::::::::==#@@@@@@@@@@@@%#@@@@@@@@@@@@@#-::::::=%@@@@@@
// @@@@@@@@=::::::-%@@@@@@@@@@=:::::::::::::::::::::::::*=#%@@@@@@@@@@@@@%#@@@@@@@@@@@@@#-::::::*@@@@@@
// @@@@@@@*::::::-#@@@@@@@@@@*::::::::::::::::::::::::*=#+%@@@%@@@@@@@@@@@%%@@@@@@@@@@@@@%-::::::*@@@@@
// @@@@@@%:::::::#@@@@@@@@@@%:::::::::::::::::::---:::-:-+*@%%@@@@@@@@@@@@@*%@@@@@@@@@@@@@%-::::::%@@@@
// @@@@@@-::::::#@@@@@@@@@@@-::::::::::::::::::::+=#-=#*#=+%%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@#-:::::-%@@@
// @@@@@*::::::*@@@@@@@@@@@#:::::::::::::::::::::-++=#==#+-%%%@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@*::::::*@@@
// @@@@%::::::-@@@@@@@@@@@@=::::::::::::::::::::::::+=++#%=%*@@@@@@@@@@@@@@@@*@@@@@@@@@@@@@@@-::::::%@@
// @@@@*::::::#@@@@@@@@@@@%:::::::::::::::::::::::::+#:+@%+%@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@%-:::::*@@
// @@@%::::::=@@@@@@@@@@@@*::::::::::::::::::::::::-#*-#+=@@%@%@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@*::::::%@
// @@@*::::::%@@@@@@@@@@@@=:::::::::::::::::::::::+=#@++=+%@@@@@@@@@@@@@@#@@@+-%@@@@@@@@@@@@@@@-:::::*@
// @@::::::*@@@@@@@@@@@@@-:::::::::::::::::::::::-**+@+*=%@%@@@@@@@@@@@#@@%=::*@@@@@@@@@@@@@@@*::::::%@
// @%::::::#@@@@@@@@@@@@@::::::::::::::::::::::::::==#@%+@%+*%%@@@@@@@#==+::=-#@@@@@@@@@@@@@@@#::::::*@
// @*:::::-@@@@@@@@@@@@@@::::::::::::::::::::::::::::***%-@*@%%@@@@@@@%%=+*%%%@@@@@@@@@@@@@@@@@-:::::+@
// @=:::::*@@@@@@@@@@@@@@-::::::::::::::::::::::::::-+@+=+*%*%@@@@@@@%@@@%*=:*@@@@@@@@@@@@@@@@@+:::::=@
// %::::::*@@@@@@@@@@@@@@*::::::::::::::::::::::-=-=+#**#=%+@@*@@@@@@@@@@@+=**%@@@@@@@@@@@@@@@@#::::::%
// %::::::%@@@@@@@@@@@@@@#:::::::::::::::::::+#@++@%@@#*+*+#=@@@@@@@@@@@@@@*%@#%@@@@@@@@@@@@@@@#::::::#
// *::::::@@@@@@@@@@@@@@@@-:::::::::::::::::*@@@:::%@@@@*---**@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@%::::::*
// *::::::@@@@@@@@@@@@@@@@+:::::::::::::::::@@@@%::*@@@@@+-:=%+@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@::::::*
// *:::::-@@@@@@@@@@@@@@@@#:::::::::::::::::%=%@@-:+@@@@@*::%*@@@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@-:::::*  
// *:::::=@@@@@@@@@@@@@@@@@+::::::::::::::::*:-@*::*-*@@@@-:-=%@%@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@::::::*
// *:::::-@@@@@@@@@@@@@@@@@%-:::::::::::::::*+:%@@:::-@@@@-:=+%%@%@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@::::::*
// *::::::%@@@@@@@@@@@@@@@@@*::::::::::::::::*=-@*::::%@@@+:+*@@@%@@@@@@@@@@@%@@%#@@@@@@@@@@@@@%::::::*
// #::::::%@@@@@@@@@@@@@@@@@%-::::::::::::::::#+**:::::%@@*:-=%@*@@@@@@@@@@@#**%@@@@@@@@@@@@@@@%::::::#
// @::::::*@@@@@@@@@@@@@@@@@@*::::::::::::::::-%@@@@@**@@%=::=+@@@@@%@@@@@@@@@%@@@@@@@@@@@@@@@@*::::::@
// @-:::::*@@@@@@@@@@@@@@@@@@@=:::::::::::::::::#@@@@@@@@%:::+=%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@*:::::-@
// @+:::::=@@@@@@@@@@@@@@@@@@@%-:::::::::::::::::*%@@@*%@-:::-*=*%@@@@@@@@@@@@@%@@@@@@@@@@@@@@@::::::*@
// @*::::::%@@@@@@@@@@@@@@@@@@@*:::::::::::::::::::=%%+#@=:::=*++@@@@@@@@@@@@@#@@@@@@@@@@@@@@@%::::::*@
// @@-:::::*@@@@@@@@@@@@@@@@@@@#::::::::::::::::----:=###::::=**%%@@@@@@@@@@@+%@@@@@@@@@@@@@@@@+:::::-@
// @@+:::::-%@@@@@@@@@@@@@@@@@@@-:::::::::::::=@@@@@+::::::::-*#%%%@@@@@@@@@%*%@@@@@@@@@@@@@@%::::::*@@
// @@#::::::*@@@@@@@@@@@@@@@@@@@+::::::::::::::%@@@@@-:::::::+%@%%%@@@@@@@@@%@@@@@@@@@@@@@@@@+::::::%@@
// @@@+::::::%@@@@@@@@@@@@@@@@@@*::::::::::::::*@@@@@-:::::::-+#@%%@%@@@@@@@%@@@@@@@@@@@@@@@%::::::=@@@
// @@@%-:::::*@@@@@@@@@@@@@@@@@@*::::::::::::::#@@@@@::::::::::*@%**%@@@@@@@#@@@@@@@@@@@@@@@=::::::%@@@
// @@@@*::::::%@@@@@@@@@@@@@@@@@*::::::::::::::*@@@@@#-::::::::===+-%%@@@@@@%%@@@@@@@@@@@@@*::::::*@@@@
// @@@@@-:::::-%@@@@@@@@@@@@@@@@+::::::::::::::=#%@@@@*--#=::::::--:=@@%%%@@%@@@@@@@@@@@@@#::::::-@@@@@
// @@@@@#-:::::-%@@@@@@@@@@@@@@@=::::::::::::::==@%@%%%#+%%*:::::::-=#%%*%@#*@@@@@@@@@@@@%:::::::#@@@@@
// @@@@@@*::::::*%@@@@@@@@@@**+-:::::::::::::::@#@@%@@@%#%@*::::-::::==::%%*@@@@@@@@@@@@%=::::::*@@@@@@
// @@@@@@@+::::::*@@@@@@@@*::::::::::::::::::-##%%@#@@@@%%%*-==*%:-::==+**@@@@@@@@@@@@@%=::::::=@@@@@@@
// @@@@@@@@-::::::*%@@@@*::::::::::::::::::::::%%%%%@@@@@@@#%@@%%@@@@@@@@@@@@@@@@@@@@@%=::::::=@@@@@@@@
// @@@@@@@@%-::::::=%@@%:::::::::::::::::::::#@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#:::::::-@@@@@@@@@
// @@@@@@@@@@-::::::-%@#::::::::::::::::::::+@@@@@%@@@@@@@@@@@%%@@@@@@@@@@@@@@@@@@@@*:::::::=@@@@@@@@@@
// @@@@@@@@@@@-:::::::*@-:::::::::::::::::::-%@@@@@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@=:::::::=@@@@@@@@@@@
// @@@@@@@@@@@@+:::::::==:::::::::::::::::::-%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@#-:::::::+@@@@@@@@@@@@
// @@@@@@@@@@@@@*-:::::::::::::::::::::::::::=@@@@@@@@@@@@@@%#@@@@@@@@@@@@@@@@@%=::::::::#@@@@@@@@@@@@@
// @@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@+::::::::=#@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@*-::::::::::::::::::::::::::*%@@@@@@@@@@*@@@@@@@@@@@@@@@@+:::::::::*@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@%=:::::::::::::::::::::::::::*%@@@@@@@@#@@@@@@@@@@@@@*=:::::::::=%@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*%@@@@@@@%#@@@@@@@@*+-:::::::::=#@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*%@@@@@@@%@@@@*+:::::::::::=#@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@#=-::::::::::::::::::::::::::+%@@@@%**--::::::::::::+#@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@%*-:::::::::::::::::::::::::::::::::::::::::::::*%@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@#*-:::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##=-:::::::::::::::::::::::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##*=-::::::::::::::::::::-+**%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%##****+++++****%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#*++==------===**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++-::::::::::::::::::::::-=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@#+::::::::::::::::::::::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@%+:::::::::::::::::=++***+=-::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@#=::::::::::::::::+%@@@@@@@@@@%+-:::::::::::::::::::=#@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@#-::::::::::::::::#@@@@@@@@@@@@@@@@%-:::::::::::::::::::=#@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@%=::::::::::::::::*@@@@@@**==-=+##@@@@@*-:::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@=:::::::::::::::::%@@@@@+::::::::::-*@@@@#-::::::::::::::::::::=@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@#::::::::::::::::::%@@@@=::::::::::::::-%@@@#-:::::::::::::::::::::#@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@=::::::::::::::::::*@@@@=::::::::::::::::-%@@@*::::::::::::::::::::::=@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@%-::::::::::::::::::-@@@@=::::::::::::::::::-%@@@-::::::::::::::::::::::-%@@@@@@@@@@@@@
// @@@@@@@@@@@@#::::::::::::::::::::*@@@#::::::::::::::::::::=@@@*::::::::::::::::::::::::*@@@@@@@@@@@@
// @@@@@@@@@@@#:::::::::::::::::::::%@@@+::::::::::::::::::::-@@@%:::::::::::::::::::::::::*@@@@@@@@@@@
// @@@@@@@@@@+::::::::::::::::::::::@@@@-:::::::::::::::::::::%@@@::::::::::::::::::::::::::*@@@@@@@@@@
// @@@@@@@@@*:::::::::::::::::::::::@@@@=:::::::::::::::::::::@@@@:::::::::::::::::::::::::::*@@@@@@@@@
// @@@@@@@@%::::::::::::::::::::::::@@@@*:::::::::::::::::::::@@@%::::::::::::::::::::::::::::*@@@@@@@@
// @@@@@@@%:::::::::::::::::::::::::@@@@%::::::::::::::::::::+@@@*:::::::::::::::::::::::::::::%@@@@@@@
// @@@@@@@::::::::::::::::::::::::::@@@@@*::::::::::::::::::-@@@@::::::::::::::::::::::::::::::-@@@@@@@
// @@@@@@=::::::::::::::::::::::::::@@@@@@*::::::::::::::::-@@@@+:::::::::::::::::::::::::::::::*@@@@@@
// @@@@@%:::::::::::::::::::::::::::@@@@@@@*::::::::::::::-%@@@#:::::::::::::::::::::::::::::::::*@@@@@
// @@@@@::::::::::::::::::::::::::::@@@@@@@@@*::::::::::+@@@@@*::::::::::::::::::::::::::::::::::-@@@@@
// @@@@*::::::::::::::::::::::::::::@@@#=@@@@@@%#*+=**%@@@@@@=::::::::::::::::::::::::::::::::::::*@@@@
// @@@@:::::::::::::::::::::::::::::@@@#::*@@@@@@@@@@@@@@@@*:::::::::::::::::::::::::::::::::::::::@@@@
// @@@*:::::::::::::::::::::::::::::@@@#::::=*@@@@@@@@@%#=:::::::::::::::::::::::::::::::::::::::::#@@@
// @@@=:::::::::::::::::::::::::::::@@@#::::::::-==+=-:::::::::::::::::::::::::::::::::::::::::::::=@@@
// @@@::::::::::::::::::::::::::::::@@@#:::::::::::::::::::::::::::::::::::::::::::::::::--:::::::::@@@
// @@*::::::::::::::::::::::::::::::@@@#:::::::::+######*:::::::::::::::::::::::::::::::+@=:::::::::#@@
// @@*::::::::::::::::::::::::::::::@@@#:::--::::===+*+==:::::=-:::::::=-::::::-::::::::+@=:::::::::+@@
// @@:::::::::::::::::::::::::::::::@@@#::+@#@@::-#@@%@%=::=@@@@+:::+@@@@@+-::@@@@%*-::#@@%#:::::::::@@
// @@:::::::::::::::::+*##%%#*=-::::@@@#::+@@=::-%@:::-*@=:%@-:=:::*@*:::-@*::@@-:=@%::=*@*=:::::::::@@
// @@::::::::::::::+%@@@@@@@@@@@%*-:@@@#::+@*:::*@@@@@@@@#:+@%*-:::@@@@@@@@@-:@%:::#@:::+@=::::::::::@@
// @%::::::::::::*@@@@@@@@@@@@@@@@@#+@@#::+@+:::+@=-------:::=%@*::@%-------::@%:::#@:::+@=::::::::::%@
// @%::::::::::-@@@@@@++-::::-=#@@@@@+*#::+@+:::-@%=-:+%%-:-=::#@::*@*-::+%=::@%:::#@:::+@=::::::::::#@
// @%:::::::::=@@@@%+::::::::::::#@@@@**::+@+::::-#@@@@%=::#@%%@+:::+@@@@@*:::@%:::#@:::+@=::::::::::%@
// @%::::::::-@@@@+:::::::::::::::-@@@@+:::-::::::::--:::::::=-:::::::-=-:::::--:::-=----=-::::::::::%@
// @@:::::::-@@@@*:::::::::::::::::-%%%*:::::::::::::::::::::::::::::::::::::::::::+%%%%%%#::::::::::@@
// @@:::::::*@@@#:::::::+#@%*-::::::=+*#*=+#*=-:::::+#%%#-::::::=#%%#=::::-#@@#-::::=##%#+-::::::::::@@
// @@-::::::@@@@-:::::-%@#+*%@*:::::%@#+#@@+*@*::::%@+==#@*::::%@#+=%@*-::%@-=*=:::*@*+=+@%-::::::::-@@
// @@+:::::-@@@@::::::#@=::::#@=::::%@::=@*::#@-::*@=::::-@+::*@*::::*@*::*@*-::::-@@####%@#::::::::*@@
// @@#:::::-@@@*::::::@@:::::=@*::::%@::=@*::#@-::%@::::::@*::%@-::::-@%:::=%@%-::*@#******+::::::::*@@
// @@@-::::-@@@%::::::#@+::::%@-::::%@::=@*::#@-::@@-::::=@-::*@*::::*@*:::-::@%::=@*::::-=-::::::::@@@
// @@@+:::::@@@@-::::::%@%*#@@+:::::%@::=@*::#@-::@@@#=+#@+::::*@%*+@@*:::#@*+@*:::*@%*+%@%::::::::-@@@
// @@@#:::::#@@@+:::::::=*##+-::::::+*::-*=::+*:::@%=*%#*-::::::=*%#*-:::::=*#+:::::-*##*=--=::::::*@@@
// @@@@-::::=@@@@-::::::::::::::::::=**+::::::::::@%:::::::::::::::::::::::-==++**##%%@@@@@@@-::::-@@@@
// @@@@*:::::*@@@@-::::::::::::::::+@@@#::::::::::::::::::::-==++**##=-#@@@@@@@@@@@@@@@@@@@@@=::::*@@@@
// @@@@@-:::::#@@@@+-:::::::::::::*@@@@::::::-==++--##%@@@@@@@@@#*#@@%%@@@@@@@@@@@#@@@@@*#@@@+:::-@@@@@
// @@@@@%::::::*@@@@@+-:::::::::+@@@@%:=@@@@@@@@@@==@@@**%@@@@*-#@*-@@*@@@*-+**@@@:%@@==@++@@*:::%@@@@@
// @@@@@@*::::::=@@@@@@@%%**##@@@@@@=::=@@@@#-:--=-=@@=+@+=@@@:%@@@=+@-*@*-@@@+:@@=#@:*@@%-@@#::+@@@@@@
// @@@@@@@-:::::::+%@@@@@@@@@@@@@@#-::::@@@+-%@@@*--@@:@@=*@@@%=*%@@@@*=@-*@@@*:+@=+=#@@@%:@@%:-@@@@@@@
// @@@@@@@@-::::::::=*%@@@@@@@##-:::::::@@@:#@@@@@*:@@:%==@@@@@@%+-%@@#-@*+@@@:+:@*:*@@@@@:%@@-@@@@@@@@
// @@@@@@@@#-:::::::::::::-:::::::::::::@@%:%@@@@@*-@@-#@@@#-@*%@@@-#@@:@@#=+:%@-#@:@@@@@@*=@@%@@@@@@@@
// @@@@@@@@@*:::::::::::::::::::::::::::#@@--@@@@%:*@@%*+*=*@@=+@@@=+@@-#@@@@@@@=#@#@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@*-:::::::::::::::::::::::::#@@@+-==-:#@@@@@@@@@@@@#++*#@@@@@@@#@@@%:@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@*-::::::::::::::::::::::::+@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@-=-:+**++==--::%@@@@@@@@@@@
// @@@@@@@@@@@@#-:::::::::::::::::::::::=@@@@@@@@@@@@@@@@@@@@@%%##**++=---::::::::::::::::%@@@@@@@@@@@@
// @@@@@@@@@@@@@@-::::::::::::::::::::::-@@@@@@%###**++=--::::::::::::::::::::::::::::::-%@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@+::::::::::::::::::::::--::::::::::::::::::::::::::::::::::::::::::::+@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@%-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-%@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@+-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@%=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@%=::::::::::::::::::::::::::::::::::::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@%=-:::::::::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@*-:::::::::::::::::::::::::::::::::::::::::::::#@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@%+-:::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*=-:::::::::::::::::::::::::::::::+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%**=-:::::::::::::::::::::=+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%**++=====+++*##@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 
-->
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div class="pp-desc-container">
    <div class="pp-desc-wrap">

        <!-- Badge lauréat -->
        <div class="pp-award-row">
            <div class="pp-laurel-badge">
                <img decoding="async"
                    src="https://presentcomposedesign.fr/wp-content/uploads/2026/03/3rd_place_svg_PresentComposedesign_NWSOPC.svg"
                    alt="3rd Place - New Worlds and Splats Open Call"
                    class="pp-laurel-img"
                />
            </div>
        </div>

        <h2 class="pp-title">Paper Plane <i class="fa-regular fa-paper-plane pp-title-icon"></i></h2>
        <p class="pp-subtitle">Mon tout premier plugin Arrival.Space. Un avatar universel pour le web immersif.</p>

        <div class="pp-divider"></div>

        <div class="pp-content">
            <div class="pp-block">
                <h3 class="pp-heading">Le concept</h3>
                <p>Paper Plane est parti d'une question simple : et si le meilleur avatar était aussi le plus universel ? Pas de personnage genré, pas de corps humanoïde. Juste un avion en papier, instinctif et léger, qui traverse librement chaque monde d'Arrival.Space.</p>
            </div>

            <div class="pp-block">
                <h3 class="pp-heading">Pourquoi un avion en papier ?</h3>
                <p>Tout le monde en a plié un. Tout le monde en a lancé un. C'est peut-être l'objet le plus démocratique qui existe. En tant qu'avatar, il efface toute friction d'identification : pas d'âge, pas de genre, pas de skin à choisir. Du mouvement pur, et une liberté totale d'exploration.</p>
            </div>

            <div class="pp-block">
                <h3 class="pp-heading">De SplatGate à Paper Plane</h3>
                <p>Ce projet s'appuie sur toute l'expertise en Gaussian Splatting que j'ai construite avec SplatGate. Paper Plane, c'est mon premier pas dans l'écosystème Arrival.Space, un nouveau terrain pour pousser les limites du web immersif, du spatial computing et du vibe coding.</p>
            </div>

            <!-- Tags compacts + VR gradient -->
            <div class="pp-tags">
                <span class="pp-tag">🧊 Gaussian Splatting</span>
                <span class="pp-tag">🌐 Web Immersif</span>
                <span class="pp-tag pp-tag-vr"><span class="pp-vr-gradient">Full VR available Experience -ᯅ-</span> ✔️</span>
            </div>
        </div>

        <!-- CTAs - 3 boutons sur une ligne -->
        <div class="pp-cta-row">
            <a href="https://arrival.space/83754293_5074?gate=608f2483-802b-4fa7-95bb-920bed1431ad" target="_blank" class="pp-cta-primary">
                Explorer les univers gagnants <i class="fa-regular fa-paper-plane"></i>
            </a>
            <a href="https://arrival.space/82998375_8446" target="_blank" class="pp-cta-secondary">
                Essayer Paper Plane
            </a>
            <a href="https://buymeacoffee.com/presentcomposedesign" target="_blank" class="pp-cta-support">
                <i class="fa-solid fa-heart pp-heart-pulse"></i> Soutenir / Remercier
            </a>
        </div>

        <!-- Partenaires -->
        <div class="pp-partners">
            <span class="pp-partners-label">Organisé par</span>
            <div class="pp-partners-logos">
                <a href="https://arrival.space/" target="_blank" class="pp-partner-block" title="Arrival.Space">
                    <img decoding="async"
                        src="https://presentcomposedesign.fr/wp-content/uploads/2026/03/arrival-space-logo-white.svg"
                        alt="Arrival.Space"
                        class="pp-partner-logo"
                    />
                    <span class="pp-partner-name">Arrival.Space</span>
                </a>
                <span class="pp-partners-sep">&</span>
                <a href="https://www.choice.love/" target="_blank" class="pp-partner-block" title="CHOICE DAO">
                    <img decoding="async"
                        src="https://presentcomposedesign.fr/wp-content/uploads/2026/03/choice-DAO-logo-1.svg"
                        alt="CHOICE DAO"
                        class="pp-partner-logo"
                    />
                    <span class="pp-partner-name">CHOICE DAO</span>
                </a>
            </div>
        </div>

    </div>
</div>
<style>
    /* Animations */
    @keyframes ppHoloFlow {
        0% { background-position: 0% 50%; }
        100% { background-position: 200% 50%; }
    }
    @keyframes ppBronzeFlow {
        0% { background-position: 0% 50%; }
        100% { background-position: 200% 50%; }
    }
    @keyframes ppHeartBeat {
        0% { transform: scale(1); }
        50% { transform: scale(1.15); }
        100% { transform: scale(1); }
    }

    .pp-desc-container {
        width: 100vw;
        position: relative;
        left: 50%;
        right: 50%;
        margin-left: -50vw;
        margin-right: -50vw;
        padding: 0;
        background: linear-gradient(175deg, #0a0e1a 0%, #111827 50%, #0f172a 100%);
        box-sizing: border-box;
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, sans-serif;
        overflow: hidden;
    }
    .pp-desc-wrap {
        max-width: 900px;
        margin: 0 auto;
        padding: 60px 40px 50px;
    }

    /* Badge lauréat */
    .pp-award-row {
        display: flex;
        justify-content: center;
        margin-bottom: 4px;
    }
    .pp-laurel-badge {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 8px;
    }
    .pp-laurel-img {
        width: 160px;
        height: auto;
        filter: drop-shadow(0 0 14px rgba(184, 122, 94, 0.35));
    }
    .pp-award-label {
        font-size: 11px;
        font-weight: 600;
        color: #C4836A;
        letter-spacing: 2.5px;
        text-transform: uppercase;
        text-align: center;
        opacity: 0.85;
    }

    /* Titre & sous-titre */
    .pp-title {
        font-size: 46px;
        font-weight: 800;
        color: #ffffff;
        margin: 0 0 10px 0;
        line-height: 1.1;
        text-align: center;
    }
    .pp-title-icon {
        font-size: 36px;
        vertical-align: middle;
        margin-left: 6px;
        color: #00BFFF;
    }
    .pp-subtitle {
        font-size: 18px;
        color: #94a3b8;
        margin: 0 0 30px 0;
        line-height: 1.5;
        text-align: center;
    }
    .pp-divider {
        width: 60px;
        height: 3px;
        background: linear-gradient(90deg, #00BFFF, #1E90FF);
        border-radius: 2px;
        margin: 0 auto 40px;
    }

    /* Contenu */
    .pp-content {
        margin-bottom: 36px;
    }
    .pp-block {
        margin-bottom: 28px;
    }
    .pp-heading {
        font-size: 18px;
        font-weight: 700;
        color: #e2e8f0;
        margin: 0 0 8px 0;
    }
    .pp-block p {
        font-size: 15px;
        color: #94a3b8;
        line-height: 1.7;
        margin: 0;
    }

    /* Tags compacts */
    .pp-tags {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        margin-top: 28px;
        justify-content: center;
    }
    .pp-tag {
        display: inline-flex;
        align-items: center;
        padding: 2px 10px;
        font-size: 11px;
        line-height: 1.4;
        font-weight: 500;
        color: #94a3b8;
        background: rgba(255, 255, 255, 0.03);
        border: 1px solid rgba(255, 255, 255, 0.06);
        border-radius: 20px;
        letter-spacing: 0.3px;
        white-space: nowrap;
    }
    .pp-tag-vr {
        gap: 4px;
    }
    .pp-vr-gradient {
        background: linear-gradient(120deg, #00F7AD, #0010EF 50%, #00F7AD);
        background-size: 200% 200%;
        animation: ppHoloFlow 5s linear infinite;
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
        font-weight: 600;
    }

    /* CTAs - 3 boutons sur une ligne */
    .pp-cta-row {
        display: flex;
        justify-content: center;
        align-items: center;
        gap: 12px;
        flex-wrap: nowrap;
        margin-bottom: 50px;
    }

    /* CTA principal - contour gradient animé bronze/or */
    .pp-cta-primary {
        position: relative;
        display: inline-flex;
        align-items: center;
        gap: 8px;
        padding: 12px 24px;
        background: rgba(255, 255, 255, 0.03);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
        color: #D4967A;
        text-decoration: none;
        font-size: 14px;
        font-weight: 700;
        border-radius: 10px;
        border: 2px solid transparent;
        transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s;
        white-space: nowrap;
    }
    .pp-cta-primary::before {
        content: "";
        position: absolute;
        inset: 0;
        border-radius: 10px;
        padding: 2px;
        background: linear-gradient(120deg, #C9A84C, #B87A5E 30%, #D4967A 60%, #C9A84C);
        background-size: 200% 200%;
        animation: ppBronzeFlow 4s linear infinite;
        -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
        -webkit-mask-composite: xor;
        mask-composite: exclude;
        z-index: -1;
    }
    .pp-cta-primary:hover {
        transform: translateY(-2px);
        box-shadow: 0 5px 20px rgba(184, 122, 94, 0.25);
    }

    .pp-cta-secondary {
        display: inline-flex;
        align-items: center;
        padding: 12px 24px;
        background: transparent;
        color: #00BFFF;
        text-decoration: none;
        font-size: 14px;
        font-weight: 700;
        border-radius: 10px;
        border: 2px solid rgba(0, 191, 255, 0.4);
        transition: all 0.3s ease;
        white-space: nowrap;
    }
    .pp-cta-secondary:hover {
        border-color: #00BFFF;
        background: rgba(0, 191, 255, 0.08);
        transform: translateY(-2px);
    }
    .pp-cta-support {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        padding: 12px 24px;
        background: rgba(255, 255, 255, 0.03);
        color: #fff;
        text-decoration: none;
        font-size: 14px;
        font-weight: 700;
        border-radius: 10px;
        border: 2px solid rgba(255, 255, 255, 0.12);
        transition: all 0.3s ease;
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
        white-space: nowrap;
    }
    .pp-cta-support:hover {
        transform: translateY(-2px);
        background: rgba(255, 255, 255, 0.08);
        border-color: rgba(255, 255, 255, 0.25);
        box-shadow: 0 0 20px rgba(255, 64, 129, 0.2);
    }
    .pp-heart-pulse {
        color: #ff4081;
        animation: ppHeartBeat 2s infinite ease-in-out;
    }

    /* Partenaires */
    .pp-partners {
        text-align: center;
        padding-top: 30px;
        border-top: 1px solid rgba(255, 255, 255, 0.06);
    }
    .pp-partners-label {
        display: block;
        font-size: 11px;
        font-weight: 600;
        color: #64748b;
        letter-spacing: 2px;
        text-transform: uppercase;
        margin-bottom: 18px;
    }
    .pp-partners-logos {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 20px;
    }
    .pp-partner-block {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 8px;
        text-decoration: none;
        opacity: 0.7;
        transition: opacity 0.3s;
    }
    .pp-partner-block:hover {
        opacity: 1;
    }
    .pp-partner-name {
        font-size: 12px;
        font-weight: 200;
        color: #94a3b8;
        letter-spacing: 0.5px;
    }
    .pp-partner-logo {
        height: 22px;
        width: auto;
        object-fit: contain;
    }
    .pp-partners-sep {
        color: #64748b;
        font-size: 20px;
        font-weight: 200;
        align-self: center;
        padding: 0 10px;
    }

    /* Responsive */
    @media (max-width: 768px) {
        .pp-desc-wrap {
            padding: 40px 20px 36px;
        }
        .pp-title {
            font-size: 30px;
        }
        .pp-title-icon {
            font-size: 24px;
        }
        .pp-subtitle {
            font-size: 16px;
        }
        .pp-cta-row {
            flex-wrap: wrap;
            flex-direction: column;
            align-items: center;
        }
        .pp-cta-primary,
        .pp-cta-secondary,
        .pp-cta-support {
            width: 100%;
            max-width: 300px;
            text-align: center;
            justify-content: center;
        }
        .pp-partners-logos {
            flex-direction: column;
            width: 80px;
            gap: 14px;
        }
        .pp-partners-sep {
            display: none;
        }
        .pp-laurel-img {
            width: 120px;
        }
    }
</style>
				</div>
				</div>
					</div>
		</header>
					</div>
		</section>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/paper-plane-mode_for_arrival-space/">Paper plane</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Labs</title>
		<link>https://presentcomposedesign.fr/labs/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 16 Mar 2026 15:19:07 +0000</pubDate>
				<category><![CDATA[Design produit]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=35979</guid>

					<description><![CDATA[<p>Cet article <a href="https://presentcomposedesign.fr/labs/">Labs</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="35979" class="elementor elementor-35979">
				<div class="elementor-element elementor-element-720b5ed e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="720b5ed" data-element_type="container" data-e-type="container">
					<div class="e-con-inner">
					</div>
				</div>
		<div class="elementor-element elementor-element-6c1039a e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="6c1039a" data-element_type="container" data-e-type="container">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-dc74ee0 elementor-widget elementor-widget-html" data-id="dc74ee0" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!DOCTYPE html>
<html>
<head>
  <style>
    * { margin: 0; padding: 0; outline: none !important; box-sizing: border-box; }
    html, body, #root { width: 100%; height: 100%; overflow: hidden; background: #000; }
    canvas { display: block; outline: none !important; }
    #canvas { position: absolute; top: 0; left: 0; }
  </style>

  <script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.183.2/build/three.module.js",
      "three/webgpu": "https://cdn.jsdelivr.net/npm/three@0.183.2/build/three.webgpu.js",
      "three/tsl": "https://cdn.jsdelivr.net/npm/three@0.183.2/build/three.tsl.js",
      "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.183.2/examples/jsm/"
    }
  }
  </script>

</head>
<body>
  <div id="root"></div>
  <script type="module" src="/scene.js"></script>
</body>
</html>				</div>
				</div>
					</div>
				</div>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/labs/">Labs</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Formations</title>
		<link>https://presentcomposedesign.fr/formations/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 14 Mar 2026 12:46:14 +0000</pubDate>
				<category><![CDATA[Design produit]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=35941</guid>

					<description><![CDATA[<p>Formations / Présent Composé Design ✓ Guide débloqué ! ✕🎨 Formation Découverte IA Débloquez le guide Entrez vos coordonnées pour accéder au guide sélectionné. PrénomNomEmailTéléphone (optionnel)Vous êtes· Choisissez ·Étudiant·ePro du design / créatifPro (autre secteur)Entrepreneur·eCurieux·se / DécouverteSecteur d&#8217;activitéCode d&#8217;accès (fourni par le formateur)Accéder au guide → 🔒 Données utilisées uniquement pour cette formation. Formations Présent Composé Design / Alban Desbarax Formations Présent Composé Design / Alban Desbarax Ateliers &#038; Ressources 🎨 TOP 10 Applications IA Génératives 2026 Les meilleures apps gratuites (téléphone &#038; desktop) pour générer des images et vidéos facilement avec l&#8217;IA. Guide interactif avec démos vidéo. GRATUIT · Guide interactif · 11 apps testées 💻 TOP 25 Applications Open Source à installer en 2026 La sélection essentielle des logiciels gratuits &#038; open source pour la création 3D, audio, vidéo, design, impression 3D, code créatif et productivité. GRATUIT · 25 logiciels · 7 catégories · Liens de téléchargement 🎬 Storyboard &#38; virtual production IA TOOLBOX 20 outils IA et 100 termes techniques pour la création de storyboards. Glossaire interactif, prompts prêts à l&#8217;emploi, liens et demos. GRATUIT · 20 outils · 100 termes · 2 onglets ← Retour aux formations ★ Incontournable / Assistant IA quotidien ★Mistral AI (Le Chat)Web · iOS · Android Assistant IA français polyvalent : texte, recherche, résumé, analyse. Idéal pour la productivité quotidienne. TexteRechercheAnalyse▶ DemoAccéder → 🖼️ Images / Génération &#038; édition 1ChatGPT + DALL·EWeb · iOS · Android Génération d&#8217;images réalistes via GPT-4o. ~3 images/jour en gratuit. Texte lisible dans les images. ImagesTexte▶ DemoAccéder → 2Google Gemini + Veo 3.1Web · iOS · Android IA multimodale Google. Images (Nano Banana) et vidéos HD avec audio natif via Flow. Gratuit et puissant. ImagesVidéosAudio▶ DemoAccéder → 3Canva IAWeb · iOS · Android Suite de design avec images (Média Magique) et vidéos IA (Veo-3). Intuitive, idéale pour débutants. ImagesVidéosDesign▶ DemoAccéder → 4Adobe FireflyWeb · Desktop Générateur images/vidéos premium d&#8217;Adobe. 25 crédits gratuits/mois. Remplissage génératif et retouche. ImagesVidéosRetouche▶ DemoAccéder → 🎬 Vidéos / Génération &#038; animation 5Luma AI (Dream Machine)Web · iOS · Android Génération vidéo réaliste à partir de texte ou d&#8217;images. Capture 3D photoréaliste avec téléphone. Vidéos3D▶ DemoAccéder → 6Runway (Gen-4)Web · iOS Outil cinématographique. Vidéo à partir de texte, images ou clips. Productions réelles. VidéosCinéma▶ DemoAccéder → 7Leonardo AIWeb · iOS · Android Générateur d&#8217;images avec nombreux modèles. 150 tokens/jour gratuits. Assets visuels. ImagesAssets▶ DemoAccéder → 8IdeogramWeb · iOS · Android Maîtrise du texte dans les images. ~40 images/semaine gratuits. Résultats créatifs. ImagesTypographie▶ DemoAccéder → 9Microsoft CopilotWeb · iOS · Android DALL·E 3 gratuit et illimité via Microsoft. Aucune inscription nécessaire. ImagesIllimité▶ DemoAccéder → 10PikaWeb · iOS Vidéos courtes créatives pour réseaux sociaux. Interface simple. VidéosSocial▶ DemoAccéder → ← Retour aux formations 💻 TOP 25 Applications Open Source &#038; Gratuites · PC 2026 🎮 3D · Moteurs · VR / XR Blender Suite 3D complète : modélisation, animation, rendu, compositing. Le standard open source. 3DAnimationRendu▶ DemoTélécharger ↓ Roblox Studio Créez vos propres jeux et expériences 3D. Plateforme massive de création interactive. Jeux3D▶ DemoTélécharger ↓ Unity / Unreal Engine Les deux moteurs de jeu de référence. Unity (C#) et Unreal (Blueprints/C++). Gratuits pour débuter. Jeux3DXR▶ DemoTélécharger ↓ Babylon.js Moteur 3D web open source par Microsoft. Créez des expériences 3D/WebXR dans le navigateur. Web3DWebXR▶ DemoTélécharger ↓ SideQuest Plateforme de sideloading pour Meta Quest. Accédez à des apps VR non officielles. VRQuest▶ DemoTélécharger ↓ 🎵 Audio · Musique · Son Reaper DAW professionnel ultra-léger. Licence d&#8217;évaluation illimitée. Plugins VST, MIDI, multitrack. DAWAudio▶ DemoTélécharger ↓ Ableton Live Lite DAW référence pour la musique électronique et le live. Version Lite gratuite avec instruments. DAWLive▶ DemoTélécharger ↓ Max MSP Environnement de programmation visuelle pour audio, MIDI, vidéo et médias interactifs. AudioVisuel▶ DemoTélécharger ↓ 🎬 Vidéo · Montage · Compositing DaVinci Resolve Suite pro complète : montage, étalonnage, VFX, mixage audio. Gratuit et très puissant. MontageVFXColor▶ DemoTélécharger ↓ CapCut Montage vidéo simple et efficace. Templates, effets, sous-titres auto. Idéal réseaux sociaux. MontageSocial▶ DemoTélécharger ↓ Natron Compositing node-based open source. Alternative à After Effects/Nuke pour le VFX. VFXCompositing▶ DemoTélécharger ↓ VLC Lecteur multimédia universel. Lit tous les formats, convertit, streame. Incontournable. LecteurConversion▶ DemoTélécharger ↓ 🎨 Design · Image · UI Figma Design d&#8217;interfaces, prototypage, collaboration temps réel. Version gratuite très généreuse. UI/UXPrototypage▶ DemoTélécharger ↓ Affinity Suite créative (Photo, Designer, Publisher). Alternative premium à Adobe, licence perpétuelle. DesignPhoto▶ DemoTélécharger ↓ XnView Visionneuse et convertisseur d&#8217;images. Supporte 500+ formats. Batch processing puissant. ImagesBatch▶ DemoTélécharger ↓ 🖨️ Impression 3D · Fabrication Bambu Studio Slicer officiel Bambu Lab. Profils optimisés, multi-couleur, interface moderne. SlicerFDM▶ DemoTélécharger ↓ Orca Slicer Fork communautaire de Bambu Studio. Compatible toutes imprimantes, très personnalisable. SlicerOpen Source▶ DemoTélécharger ↓ Cura (UltiMaker) Slicer universel le plus utilisé au monde. Marketplace de plugins, profils communautaires. SlicerUniversel▶ DemoTélécharger ↓ ⚡ Code créatif · IA générative TouchDesigner Programmation visuelle temps réel pour installations interactives, VJing, mapping. InteractifTemps réel▶ DemoTélécharger ↓ Processing Langage de programmation créative. Idéal pour apprendre le code par le visuel. CodeArt▶ DemoTélécharger ↓ Arduino Plateforme électronique open source. IDE + cartes pour prototypage interactif. ÉlectroniqueIoT▶ DemoTélécharger ↓ ComfyUI Interface node-based pour Stable Diffusion. Workflows visuels pour la génération d&#8217;images IA. IAStable Diffusion▶ DemoTélécharger ↓ 🔧 Outils · Productivité · Communication Visual Studio Code Éditeur de code le plus populaire. Extensions, Git, terminal intégré, IA (Copilot). CodeIDE▶ DemoTélécharger ↓ OpenOffice Suite bureautique complète et gratuite. Writer, Calc, Impress. Alternative à Microsoft Office. BureauDocs▶ DemoTélécharger ↓ Discord Plateforme de communication. Salons vocaux/texte, partage d&#8217;écran, bots, communautés. ChatCommunauté▶ DemoTélécharger ↓ ← Retour aux formations 🎬 STORYBOARD &#038; VIRTUAL PRODUCTION IA TOOLBOX e.classList.remove(&#8216;active&#8217;));this.classList.add(&#8216;active&#8217;);document.getElementById(&#8216;sb-outils&#8217;).classList.add(&#8216;active&#8217;) »>🛠 Outils (20) e.classList.remove(&#8216;active&#8217;));this.classList.add(&#8216;active&#8217;);document.getElementById(&#8216;sb-glossaire&#8217;).classList.add(&#8216;active&#8217;) »>📖 Glossaire (100) 🖼️ Génération d&#8217;images 1ComfyUIGratuit Interface node-based pour Stable Diffusion et Flux. Workflows visuels puissants pour la génération d&#8217;images IA. Personnalisation totale, ControlNet, IP-Adapter, cohérence entre panels. Workflow visuelStable DiffusionControlNetCohérence▶ DemoAccéder →this.style.outline= »,1000) » data-p= »ControlNet pose + IP-Adapter style: Generate storyboard panel, plan rapproché, dutch angle 15°, hard side lighting, clair-obscur, background defocused urban décor, cinematic 16:9, high contrast B&#38;W storyboard sketch style » title= »Copier »>PROMPT · clic = copierControlNet pose + IP-Adapter style: Generate storyboard panel, plan rapproché, dutch angle 15°, hard side</p>
<p>Cet article <a href="https://presentcomposedesign.fr/formations/">Formations</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="35941" class="elementor elementor-35941">
				<div class="elementor-element elementor-element-25c13e0 e-con-full e-flex wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="25c13e0" data-element_type="container" data-e-type="container">
				<div class="elementor-element elementor-element-4ebd579 elementor-widget__width-inherit elementor-widget elementor-widget-html" data-id="4ebd579" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					
<!--
╔═══════════════════════════════════════════════════════════════╗
║ Formations / Présent Composé Design, © All rights reserved.   ║
║---------------------------------------------------------------║
║ Dev-Xprmnts · VR_Xprmnts, Present Compound Design             ║
║ Alban DESBARAX - Designer 360° //* Creative Technologist      ║
║ Toulouse, FRANCE                                              ║
║                                                               ║
║   · Expertise & Support 2D, 3D, AR, VR, XR, AI               ║
║   · Product Design & Industrial Design                        ║
║   · Digital communication                                     ║
║   · Immersive experiences  -ᯅ- ✔️                            ║
║                                                               ║
║ · 🡺 https://presentcomposedesign.fr/                         ║
╚═══════════════════════════════════════════════════════════════╝

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#*++==------===**%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++-::::::::::::::::::::::-=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+::::::::::::::::::::::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@%+:::::::::::::::::=++***+=-::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@#=::::::::::::::::+%@@@@@@@@@@%+-:::::::::::::::::::=#@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@#-::::::::::::::::#@@@@@@@@@@@@@@@@%-:::::::::::::::::::=#@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@%=::::::::::::::::*@@@@@@**==-=+##@@@@@*-:::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@=:::::::::::::::::%@@@@@+::::::::::-*@@@@#-::::::::::::::::::::=@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@#::::::::::::::::::%@@@@=::::::::::::::-%@@@#-:::::::::::::::::::::#@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@=::::::::::::::::::*@@@@=::::::::::::::::-%@@@*::::::::::::::::::::::=@@@@@@@@@@@@@@@
@@@@@@@@@@@@@%-::::::::::::::::::-@@@@=::::::::::::::::::-%@@@-::::::::::::::::::::::-%@@@@@@@@@@@@@
@@@@@@@@@@@@#::::::::::::::::::::*@@@#::::::::::::::::::::=@@@*::::::::::::::::::::::::*@@@@@@@@@@@@
@@@@@@@@@@@#:::::::::::::::::::::%@@@+::::::::::::::::::::-@@@%:::::::::::::::::::::::::*@@@@@@@@@@@
@@@@@@@@@@+::::::::::::::::::::::@@@@-:::::::::::::::::::::%@@@::::::::::::::::::::::::::*@@@@@@@@@@
@@@@@@@@@*:::::::::::::::::::::::@@@@=:::::::::::::::::::::@@@@:::::::::::::::::::::::::::*@@@@@@@@@
@@@@@@@@%::::::::::::::::::::::::@@@@*:::::::::::::::::::::@@@%::::::::::::::::::::::::::::*@@@@@@@@
@@@@@@@%:::::::::::::::::::::::::@@@@%::::::::::::::::::::+@@@*:::::::::::::::::::::::::::::%@@@@@@@
@@@@@@@::::::::::::::::::::::::::@@@@@*::::::::::::::::::-@@@@::::::::::::::::::::::::::::::-@@@@@@@
@@@@@@=::::::::::::::::::::::::::@@@@@@*::::::::::::::::-@@@@+:::::::::::::::::::::::::::::::*@@@@@@
@@@@@%:::::::::::::::::::::::::::@@@@@@@*::::::::::::::-%@@@#:::::::::::::::::::::::::::::::::*@@@@@
@@@@@::::::::::::::::::::::::::::@@@@@@@@@*::::::::::+@@@@@*::::::::::::::::::::::::::::::::::-@@@@@
@@@@*::::::::::::::::::::::::::::@@@#=@@@@@@%#*+=**%@@@@@@=::::::::::::::::::::::::::::::::::::*@@@@
@@@@:::::::::::::::::::::::::::::@@@#::*@@@@@@@@@@@@@@@@*:::::::::::::::::::::::::::::::::::::::@@@@
@@@*:::::::::::::::::::::::::::::@@@#::::=*@@@@@@@@@%#=:::::::::::::::::::::::::::::::::::::::::#@@@
@@@=:::::::::::::::::::::::::::::@@@#::::::::-==+=-:::::::::::::::::::::::::::::::::::::::::::::=@@@
@@@::::::::::::::::::::::::::::::@@@#:::::::::::::::::::::::::::::::::::::::::::::::::--:::::::::@@@
@@*::::::::::::::::::::::::::::::@@@#:::::::::+######*:::::::::::::::::::::::::::::::+@=:::::::::#@@
@@*::::::::::::::::::::::::::::::@@@#:::--::::===+*+==:::::=-:::::::=-::::::-::::::::+@=:::::::::+@@
@@:::::::::::::::::::::::::::::::@@@#::+@#@@::-#@@%@%=::=@@@@+:::+@@@@@+-::@@@@%*-::#@@%#:::::::::@@
@@:::::::::::::::::+*##%%#*=-::::@@@#::+@@=::-%@:::-*@=:%@-:=:::*@*:::-@*::@@-:=@%::=*@*=:::::::::@@
@@::::::::::::::+%@@@@@@@@@@@%*-:@@@#::+@*:::*@@@@@@@@#:+@%*-:::@@@@@@@@@-:@%:::#@:::+@=::::::::::@@
@%::::::::::::*@@@@@@@@@@@@@@@@@#+@@#::+@+:::+@=-------:::=%@*::@%-------::@%:::#@:::+@=::::::::::%@
@%::::::::::-@@@@@@++-::::-=#@@@@@+*#::+@+:::-@%=-:+%%-:-=::#@::*@*-::+%=::@%:::#@:::+@=::::::::::#@
@%:::::::::=@@@@%+::::::::::::#@@@@**::+@+::::-#@@@@%=::#@%%@+:::+@@@@@*:::@%:::#@:::+@=::::::::::%@
@%::::::::-@@@@+:::::::::::::::-@@@@+:::-::::::::--:::::::=-:::::::-=-:::::--:::-=----=-::::::::::%@
@@:::::::-@@@@*:::::::::::::::::-%%%*:::::::::::::::::::::::::::::::::::::::::::+%%%%%%#::::::::::@@
@@:::::::*@@@#:::::::+#@%*-::::::=+*#*=+#*=-:::::+#%%#-::::::=#%%#=::::-#@@#-::::=##%#+-::::::::::@@
@@-::::::@@@@-:::::-%@#+*%@*:::::%@#+#@@+*@*::::%@+==#@*::::%@#+=%@*-::%@-=*=:::*@*+=+@%-::::::::-@@
@@+:::::-@@@@::::::#@=::::#@=::::%@::=@*::#@-::*@=::::-@+::*@*::::*@*::*@*-::::-@@####%@#::::::::*@@
@@#:::::-@@@*::::::@@:::::=@*::::%@::=@*::#@-::%@::::::@*::%@-::::-@%:::=%@%-::*@#******+::::::::*@@
@@@-::::-@@@%::::::#@+::::%@-::::%@::=@*::#@-::@@-::::=@-::*@*::::*@*:::-::@%::=@*::::-=-::::::::@@@
@@@+:::::@@@@-::::::%@%*#@@+:::::%@::=@*::#@-::@@@#=+#@+::::*@%*+@@*:::#@*+@*:::*@%*+%@%::::::::-@@@
@@@#:::::#@@@+:::::::=*##+-::::::+*::-*=::+*:::@%=*%#*-::::::=*%#*-:::::=*#+:::::-*##*=--=::::::*@@@
@@@@-::::=@@@@-::::::::::::::::::=**+::::::::::@%:::::::::::::::::::::::-==++**##%%@@@@@@@-::::-@@@@
@@@@*:::::*@@@@-::::::::::::::::+@@@#::::::::::::::::::::-==++**##=-#@@@@@@@@@@@@@@@@@@@@@=::::*@@@@
@@@@@-:::::#@@@@+-:::::::::::::*@@@@::::::-==++--##%@@@@@@@@@#*#@@%%@@@@@@@@@@@@@@@@@@@@@+:::-@@@@@
@@@@@%::::::*@@@@@+-:::::::::+@@@@%:=@@@@@@@@@@==@@@**%@@@@*-#@*-@@*@@@*-+**@@@:%@@==@++@@*:::%@@@@@
@@@@@@*::::::=@@@@@@@%%**##@@@@@@=::=@@@@#-:--=-=@@=+@+=@@@:%@@@=+@-*@*-@@@+:@@=#@:*@@%-@@#::+@@@@@@
@@@@@@@-:::::::+%@@@@@@@@@@@@@@#-::::@@@+-%@@@*--@@:@@=*@@@%=*%@@@@*=@-*@@@*:+@=+=#@@@%:@@%:-@@@@@@@
@@@@@@@@-::::::::=*%@@@@@@@##-:::::::@@@:#@@@@@*:@@:%==@@@@@@%+-%@@#-@*+@@@:+:@*:*@@@@@:%@@-@@@@@@@@
@@@@@@@@#-:::::::::::::-:::::::::::::@@%:%@@@@@*-@@-#@@@#-@*%@@@-#@@:@@#=+:%@-#@:@@@@@@*=@@%@@@@@@@@
@@@@@@@@@*:::::::::::::::::::::::::::#@@--@@@@%:*@@%*+*=*@@=+@@@=+@@-#@@@@@@@=#@#@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@*-:::::::::::::::::::::::::#@@@+-==-:#@@@@@@@@@@@@#++*#@@@@@@@#@@@%:@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@*-::::::::::::::::::::::::+@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@-=-:+**++==--::%@@@@@@@@@@@
@@@@@@@@@@@@#-:::::::::::::::::::::::=@@@@@@@@@@@@@@@@@@@@@%%##**++=---::::::::::::::::%@@@@@@@@@@@@
@@@@@@@@@@@@@@-::::::::::::::::::::::-@@@@@@%###**++=--::::::::::::::::::::::::::::::-%@@@@@@@@@@@@@
@@@@@@@@@@@@@@@+::::::::::::::::::::::--::::::::::::::::::::::::::::::::::::::::::::+@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@%-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-%@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@+-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@%=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@%=::::::::::::::::::::::::::::::::::::::::::::::::::::::=%@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@%=-:::::::::::::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@*-:::::::::::::::::::::::::::::::::::::::::::::#@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+-:::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*=-:::::::::::::::::::::::::::::::+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%**=-:::::::::::::::::::::=+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%**++=====+++*##@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#****+++++****##%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**+-::::::::::::::::::::==*#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+-::::::::::::::::::::::::::::::==#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-::::::::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@*-::::::::::::::::::::::::::::::::::::::::::::=*%@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@#+:::::::::::::::++****%%@@@@@%%##**=--:::::::::::::=#@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@*=:::::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@#*=-:::::::::::=#@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@#=:::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#=-::::::::::=#@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@%=::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*=::::::::::=%@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@*::::::::::*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+-:::::::::*%@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@%=::::::::=*@@@@@@@@@@@@@@%#*********#%%@@@@@@@@@@@@@@@@@@@%+-::::::::=%@@@@@@@@@@@@@@
@@@@@@@@@@@@@#:::::::::#@@@@@@@@@@@**+-::::::::::::::::-+#%@%@@@@@@@@@@@@@@%+-::::::::*@@@@@@@@@@@@@
@@@@@@@@@@@@+::::::::+@@@@@@@@@@*-::::::::::::::::::::::#@@@##%%@@@@@@@@@@@@@@+::::::::*%@@@@@@@@@@@
@@@@@@@@@@@=:::::::=#@@@@@@@@@+::::::::::::::::::::::::-*@@@@@@#%%@@@@@@@@@@@@@*-:::::::=%@@@@@@@@@@
@@@@@@@@@@=:::::::*@@@@@@@@@%=::::::::::::::::::::::::::*@@@@@@@@##%@@@@@@@@@@@@%+:::::::=%@@@@@@@@@
@@@@@@@@%=:::::::#@@@@@@@@@%:::::::::::::::::::::::::::+@@@@@@@@@@@%%@@@@@@@@@@@@@*-::::::-%@@@@@@@@
@@@@@@@@=::::::-#@@@@@@@@@%-:::::::::::::::::::::::::==#@@@@@@@@@@@@%#@@@@@@@@@@@@@#-::::::=%@@@@@@@
@@@@@@@=::::::-%@@@@@@@@@@=:::::::::::::::::::::::::*=#%@@@@@@@@@@@@@%#@@@@@@@@@@@@@#-::::::*@@@@@@@
@@@@@@*::::::-#@@@@@@@@@@*::::::::::::::::::::::::*=#+%@@@%@@@@@@@@@@@%%@@@@@@@@@@@@@%-::::::*@@@@@@
@@@@@%:::::::#@@@@@@@@@@%:::::::::::::::::::---:::-:-+*@%%@@@@@@@@@@@@@*%@@@@@@@@@@@@@%-::::::%@@@@@
@@@@@-::::::#@@@@@@@@@@@-::::::::::::::::::::+=#-=#*#=+%%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@#-:::::-%@@@@
@@@@*::::::*@@@@@@@@@@@#:::::::::::::::::::::-++=#==#+-%%%@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@*::::::*@@@@
@@@%::::::-@@@@@@@@@@@@=::::::::::::::::::::::::+=++#%=%*@@@@@@@@@@@@@@@@*@@@@@@@@@@@@@@@-::::::%@@@
@@@*::::::#@@@@@@@@@@@%:::::::::::::::::::::::::+#:+@%+%@@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@%-:::::*@@@
@@%::::::=@@@@@@@@@@@@*::::::::::::::::::::::::-#*-#+=@@%@%@@@@@@@@@@@@@@@#@@@@@@@@@@@@@@@*::::::%@@
@@*::::::%@@@@@@@@@@@@=:::::::::::::::::::::::+=#@++=+%@@@@@@@@@@@@@@#@@@+-%@@@@@@@@@@@@@@@-:::::*@@
@@::::::*@@@@@@@@@@@@@-:::::::::::::::::::::::-**+@+*=%@%@@@@@@@@@@@#@@%=::*@@@@@@@@@@@@@@@*::::::%@
@%::::::#@@@@@@@@@@@@@::::::::::::::::::::::::::==#@%+@%+*%%@@@@@@@#==+::=-#@@@@@@@@@@@@@@@#::::::*@
@*:::::-@@@@@@@@@@@@@@::::::::::::::::::::::::::::***%-@*@%%@@@@@@@%%=+*%%%@@@@@@@@@@@@@@@@@-:::::+@
@=:::::*@@@@@@@@@@@@@@-::::::::::::::::::::::::::-+@+=+*%*%@@@@@@@%@@@%*=:*@@@@@@@@@@@@@@@@@+:::::=@
%::::::*@@@@@@@@@@@@@@*::::::::::::::::::::::-=-=+#**#=%+@@*@@@@@@@@@@@+=**%@@@@@@@@@@@@@@@@#::::::%
%::::::%@@@@@@@@@@@@@@#:::::::::::::::::::+#@++@%@@#*+*+#=@@@@@@@@@@@@@@*%@#%@@@@@@@@@@@@@@@#::::::#
*::::::@@@@@@@@@@@@@@@@-:::::::::::::::::*@@@:::%@@@@*---**@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@%::::::*
*::::::@@@@@@@@@@@@@@@@+:::::::::::::::::@@@@%::*@@@@@+-:=%+@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@::::::*
*:::::-@@@@@@@@@@@@@@@@#:::::::::::::::::%=%@@-:+@@@@@*::%*@@@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@-:::::*
*:::::=@@@@@@@@@@@@@@@@@+::::::::::::::::*:-@*::*-*@@@@-:-=%@%@@@@@@@@@@@@@@@@@#@@@@@@@@@@@@@::::::*
*:::::-@@@@@@@@@@@@@@@@@%-:::::::::::::::*+:%@@:::-@@@@-:=+%%@%@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@::::::*
*::::::%@@@@@@@@@@@@@@@@@*::::::::::::::::*=-@*::::%@@@+:+*@@@%@@@@@@@@@@@%@@%#@@@@@@@@@@@@@%::::::*
#::::::%@@@@@@@@@@@@@@@@@%-::::::::::::::::#+**:::::%@@*:-=%@*@@@@@@@@@@@#**%@@@@@@@@@@@@@@@%::::::#
@::::::*@@@@@@@@@@@@@@@@@@*::::::::::::::::-%@@@@@**@@%=::=+@@@@@%@@@@@@@@@%@@@@@@@@@@@@@@@@*::::::@
@-:::::*@@@@@@@@@@@@@@@@@@@=:::::::::::::::::#@@@@@@@@%:::+=%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@*:::::-@
@+:::::=@@@@@@@@@@@@@@@@@@@%-:::::::::::::::::*%@@@*%@-:::-*=*%@@@@@@@@@@@@@%@@@@@@@@@@@@@@@::::::*@
@*::::::%@@@@@@@@@@@@@@@@@@@*:::::::::::::::::::=%%+#@=:::=*++@@@@@@@@@@@@@#@@@@@@@@@@@@@@@%::::::*@
@@-:::::*@@@@@@@@@@@@@@@@@@@#::::::::::::::::----:=###::::=**%%@@@@@@@@@@@+%@@@@@@@@@@@@@@@+:::::-@@
@@+:::::-%@@@@@@@@@@@@@@@@@@@-:::::::::::::=@@@@@+::::::::-*#%%%@@@@@@@@@%*%@@@@@@@@@@@@@@%::::::*@@
@@#::::::*@@@@@@@@@@@@@@@@@@@+::::::::::::::%@@@@@-:::::::+%@%%%@@@@@@@@@%@@@@@@@@@@@@@@@@+::::::%@@
@@@+::::::%@@@@@@@@@@@@@@@@@@*::::::::::::::*@@@@@-:::::::-+#@%%@%@@@@@@@%@@@@@@@@@@@@@@@%::::::=@@@
@@@%-:::::*@@@@@@@@@@@@@@@@@@*::::::::::::::#@@@@@::::::::::*@%**%@@@@@@@#@@@@@@@@@@@@@@@=::::::%@@@
@@@@*::::::%@@@@@@@@@@@@@@@@@*::::::::::::::*@@@@@#-::::::::===+-%%@@@@@@%%@@@@@@@@@@@@@*::::::*@@@@
@@@@@-:::::-%@@@@@@@@@@@@@@@@+::::::::::::::=#%@@@@*--#=::::::--:=@@%%%@@%@@@@@@@@@@@@@#::::::-@@@@@
@@@@@#-:::::-%@@@@@@@@@@@@@@@=::::::::::::::==@%@%%%#+%%*:::::::-=#%%*%@#*@@@@@@@@@@@@%:::::::#@@@@@
@@@@@@*::::::*%@@@@@@@@@@**+-:::::::::::::::@#@@%@@@%#%@*::::-::::==::%%*@@@@@@@@@@@@%=::::::*@@@@@@
@@@@@@@+::::::*@@@@@@@@*::::::::::::::::::-##%%@#@@@@%%%*-==*%:-::==+**@@@@@@@@@@@@@%=::::::=@@@@@@@
@@@@@@@@-::::::*%@@@@*::::::::::::::::::::::%%%%%@@@@@@@#%@@%%@@@@@@@@@@@@@@@@@@@@@%=::::::=@@@@@@@@
@@@@@@@@%-::::::=%@@%:::::::::::::::::::::#@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#:::::::-@@@@@@@@@
@@@@@@@@@@-::::::-%@#::::::::::::::::::::+@@@@@%@@@@@@@@@@@%%@@@@@@@@@@@@@@@@@@@@*:::::::=@@@@@@@@@@
@@@@@@@@@@@-:::::::*@-:::::::::::::::::::-%@@@@@@@@@@@@@@@@*@@@@@@@@@@@@@@@@@@@@=:::::::=@@@@@@@@@@@
@@@@@@@@@@@@+:::::::==:::::::::::::::::::-%@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@#-:::::::+@@@@@@@@@@@@
@@@@@@@@@@@@@*-:::::::::::::::::::::::::::=@@@@@@@@@@@@@@%#@@@@@@@@@@@@@@@@@%=::::::::#@@@@@@@@@@@@@
@@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*@@@@@@@@@@@@#@@@@@@@@@@@@@@@@@@+::::::::=#@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@*-::::::::::::::::::::::::::*%@@@@@@@@@@*@@@@@@@@@@@@@@@@+:::::::::*@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@%=:::::::::::::::::::::::::::*%@@@@@@@@#@@@@@@@@@@@@@*=:::::::::=%@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*%@@@@@@@%#@@@@@@@@*+-:::::::::=#@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@#-:::::::::::::::::::::::::::*%@@@@@@@%@@@@*+:::::::::::=#@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@#=-::::::::::::::::::::::::::+%@@@@%**--::::::::::::+#@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@%*-:::::::::::::::::::::::::::::::::::::::::::::*%@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@#*-:::::::::::::::::::::::::::::::::::::::+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##=-:::::::::::::::::::::::::::::::+*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##*=-::::::::::::::::::::-+**%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%##****+++++****%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-->
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>Formations / Présent Composé Design</title><link rel="icon" href="https://presentcomposedesign.fr/wp-content/uploads/2024/03/cropped-logo_PCd_2024-32x32.png" sizes="32x32"><link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet"><script type="module" src="https://unpkg.com/@splinetool/viewer@1.12.69/build/spline-viewer.js"></script>
<style>
:root{--pcd:#1001EF;--pcd-dk:#0C01B8;--pcd-lt:#E8E5FF;--pcd-glow:rgba(16,1,239,.15);--pcd-or:#FF6B35;--pcd-or-lt:#FFF3ED;--pcd-or-bd:#FFD0B5;--pcd-bg:#F4F3FA;--pcd-w:#FFF;--pcd-tx:#1A1A2E;--pcd-txm:#4A4A66;--pcd-txl:#8888AA;--pcd-bd:#DDDDE8;--pcd-ok:#10B981;--pcd-r:14px}
#pcd,#pcd *,#pcd *::before,#pcd *::after{margin:0;padding:0;box-sizing:border-box;border:none;outline:none;text-decoration:none;font-style:normal;list-style:none;background:none;letter-spacing:normal;text-transform:none;text-shadow:none;box-shadow:none;float:none;max-width:none;min-height:0}
#pcd{font-family:'DM Sans',sans-serif!important;background:var(--pcd-bg)!important;color:var(--pcd-tx)!important;line-height:1.6!important;font-size:16px!important;text-align:left!important;min-height:100vh;overflow-x:hidden}
#pcd .H{position:relative;overflow:hidden;min-height:480px}
#pcd .H spline-viewer{position:absolute;inset:0;width:100%;height:100%;z-index:0;pointer-events:auto}
#pcd .H::after{content:'';position:absolute;bottom:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--pcd-or),#FFD700,var(--pcd-or));z-index:3}
#pcd .Hi{max-width:900px;margin:0 auto;padding:24px 32px;display:flex;align-items:center;justify-content:space-between;gap:24px;position:relative;z-index:2}
#pcd .Hl{display:flex;align-items:center;gap:14px}
/* Logos: hidden on screen by default, shown on print */
#pcd .Lp{width:64px;height:64px;flex-shrink:0;border-radius:10px;overflow:hidden;box-shadow:0 2px 10px rgba(0,0,0,.3);background:#fff;display:none}
#pcd .Lp.show-screen{display:block}
#pcd .Lp img{width:100%;height:100%;object-fit:contain;display:block}
#pcd .Ht h1{color:#FFF!important;font-size:34px!important;font-weight:700!important;line-height:1.2!important;margin:0!important;text-shadow:0 2px 16px rgba(0,0,0,.4)}
#pcd .Ht p{color:rgba(255,255,255,.8)!important;font-size:14px!important;margin:6px 0 0!important;text-shadow:0 1px 8px rgba(0,0,0,.4)}
#pcd .Ll{width:72px;height:72px;background:rgba(255,255,255,.15);backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.2)!important;border-radius:12px;display:none;align-items:center;justify-content:center;flex-shrink:0;overflow:hidden}
#pcd .Ll.show-screen{display:flex}
#pcd .Ll img{width:100%;height:100%;object-fit:contain;padding:5px;display:block}
#pcd .land{max-width:900px;margin:0 auto;padding:40px 24px}
#pcd .land-title{font-size:14px!important;font-weight:700!important;text-transform:uppercase;letter-spacing:1.5px;color:var(--pcd)!important;margin-bottom:20px}
#pcd .fcard{background:var(--pcd-w);border:1.5px solid var(--pcd-bd)!important;border-radius:var(--pcd-r);padding:28px 70px 28px 24px;cursor:pointer;transition:transform .2s,box-shadow .2s,border-color .2s;position:relative;overflow:hidden}
#pcd .fcard:hover{transform:translateY(-3px);box-shadow:0 12px 35px rgba(16,1,239,.1)!important;border-color:var(--pcd)!important}
#pcd .fcard::before{content:'';position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--pcd),var(--pcd-or))}
#pcd .fcard h2{font-size:22px!important;font-weight:700!important;color:var(--pcd-tx)!important;margin-bottom:6px!important}
#pcd .fcard .fdesc{font-size:14.5px!important;color:var(--pcd-txm)!important;line-height:1.5!important;margin-bottom:12px!important}
#pcd .fcard .fbadge{display:inline-block;background:var(--pcd-lt);color:var(--pcd)!important;font-size:11px!important;font-weight:600!important;padding:4px 12px;border-radius:6px}
#pcd .fcard .farrow{position:absolute;right:24px;top:50%;transform:translateY(-50%);width:32px;height:32px;background:var(--pcd)!important;border-radius:50%;display:flex;align-items:center;justify-content:center}
#pcd .fcard .farrow svg{width:14px;height:14px;fill:none;stroke:#fff;stroke-width:2.5}
#pcd .fo{position:fixed;inset:0;background:rgba(10,10,26,.88);backdrop-filter:blur(14px);z-index:99999;display:none;align-items:center;justify-content:center;padding:20px;animation:pF .4s}
#pcd .fo.on{display:flex}
@keyframes pF{from{opacity:0}to{opacity:1}}
#pcd .fc{background:#fff;border-radius:22px;padding:36px 32px;max-width:440px;width:100%;box-shadow:0 30px 80px rgba(0,0,0,.5);animation:pU .5s;position:relative;overflow:hidden}
#pcd .fc::before{content:'';position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,var(--pcd),var(--pcd-or))}
@keyframes pU{from{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}
#pcd .fc h2{font-size:20px!important;font-weight:700!important;color:#0A0A1A!important;margin:4px 0!important}
#pcd .fs{color:var(--pcd-txm)!important;font-size:13px!important;margin-bottom:20px!important;line-height:1.5!important}
#pcd .fs strong{color:var(--pcd)!important}
#pcd .fg{margin-bottom:12px}
#pcd .fg label{display:block;font-size:11px!important;font-weight:600!important;color:var(--pcd-txm)!important;margin-bottom:3px!important;text-transform:uppercase;letter-spacing:.5px}
#pcd .fg label .op{font-weight:400!important;text-transform:none;color:var(--pcd-txl)!important;font-size:10px!important}
#pcd .fg input,#pcd .fg select{width:100%;padding:10px 12px;border:1.5px solid var(--pcd-bd)!important;border-radius:8px;font-family:'DM Sans',sans-serif!important;font-size:13.5px!important;color:var(--pcd-tx)!important;background:#FAFAFF!important;height:auto;-webkit-appearance:none}
#pcd .fg select{-webkit-appearance:menulist;appearance:menulist}
#pcd .fg input:focus,#pcd .fg select:focus{border-color:var(--pcd)!important;box-shadow:0 0 0 3px var(--pcd-glow)!important}
#pcd .fg input::placeholder{color:#BBB!important}
#pcd .fr{display:flex;gap:10px}
#pcd .fr .fg{flex:1}
#pcd .sf{max-height:0;overflow:hidden;transition:max-height .3s,opacity .3s;opacity:0}
#pcd .sf.v{max-height:70px;opacity:1}
#pcd .fb{display:inline-flex;align-items:center;gap:5px;background:var(--pcd-lt);border:1px solid rgba(16,1,239,.15)!important;border-radius:7px;padding:6px 12px;margin-bottom:16px;font-size:11px!important;color:var(--pcd)!important;font-weight:600!important}
#pcd .btn{width:100%;padding:13px;border:none!important;border-radius:9px;background:var(--pcd)!important;color:#fff!important;font-family:'DM Sans',sans-serif!important;font-size:14px!important;font-weight:600!important;cursor:pointer;margin-top:4px;display:block;text-align:center}
#pcd .btn:hover{transform:translateY(-1px);box-shadow:0 6px 24px rgba(16,1,239,.35)!important;background:var(--pcd-dk)!important}
#pcd .fn{text-align:center;font-size:10px!important;color:var(--pcd-txl)!important;margin-top:12px!important;line-height:1.5!important}
#pcd .fcl{position:absolute;top:14px;right:14px;width:28px;height:28px;border-radius:50%;background:rgba(0,0,0,.06)!important;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:16px!important;color:var(--pcd-txl)!important}
#pcd .guide{max-width:900px;margin:0 auto;padding:0 24px 40px;display:none}
#pcd .guide.on{display:block}
#pcd .sl{display:flex;align-items:center;gap:8px;padding:22px 0 10px;font-size:11px!important;font-weight:700!important;text-transform:uppercase;letter-spacing:1.2px;color:var(--pcd-or)!important}
#pcd .sl::after{content:'';flex:1;height:1.5px;background:linear-gradient(90deg,var(--pcd-or-bd),transparent)}
#pcd .st{display:flex;align-items:center;gap:8px;padding:24px 0 12px;font-size:11px!important;font-weight:700!important;text-transform:uppercase;letter-spacing:1.2px;color:var(--pcd)!important}
#pcd .st::after{content:'';flex:1;height:2px;background:linear-gradient(90deg,var(--pcd),transparent)}
#pcd .ac{background:var(--pcd-w);border:1px solid var(--pcd-bd)!important;border-radius:var(--pcd-r);padding:16px 18px;margin-bottom:8px;display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap;transition:all .25s;position:relative}
#pcd .ac:hover{box-shadow:0 8px 28px rgba(16,1,239,.08)!important;border-color:rgba(16,1,239,.25)!important}
#pcd .ac.mc{background:var(--pcd-or-lt);border:1.5px solid var(--pcd-or-bd)!important}
#pcd .ac.mc:hover{border-color:var(--pcd-or)!important;box-shadow:0 8px 25px rgba(255,107,53,.12)!important}
#pcd .an{width:18px;flex-shrink:0;font-family:'Space Mono',monospace!important;font-size:11px!important;font-weight:700!important;color:var(--pcd-txl)!important;text-align:center;padding-top:10px}
#pcd .mc .an{color:var(--pcd-or)!important;font-size:14px!important}
#pcd .ai{width:44px;height:44px;border-radius:10px;flex-shrink:0;overflow:hidden;background:#F0F0F5;box-shadow:0 2px 6px rgba(0,0,0,.08);display:flex;align-items:center;justify-content:center}
#pcd .ai img{width:30px;height:30px;object-fit:contain;display:block}
#pcd .ab{flex:1;min-width:0}
#pcd .ah{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap;margin-bottom:2px}
#pcd .nm{font-size:15px!important;font-weight:700!important;color:var(--pcd-tx)!important}
#pcd .mc .nm{color:#B83800!important}
#pcd .pl{font-size:9.5px!important;color:var(--pcd-txl)!important;background:rgba(0,0,0,.04)!important;padding:1px 6px;border-radius:3px}
#pcd .ad{font-size:13.5px!important;color:var(--pcd-txm)!important;line-height:1.45!important;margin-bottom:6px!important}
#pcd .af{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:6px}
#pcd .at{display:flex;gap:4px;flex-wrap:wrap}
#pcd .tg{font-size:10.5px!important;font-weight:600!important;padding:2px 8px;border-radius:4px;display:inline-block}
#pcd .ctas{display:flex;gap:6px;align-items:center}
#pcd .cta-d,#pcd .cta-a{font-size:10.5px!important;font-weight:600!important;padding:4px 10px;border-radius:6px;cursor:pointer;display:inline-flex;align-items:center;gap:3px;transition:all .15s;text-decoration:none!important}
#pcd .cta-d{background:var(--pcd-lt)!important;color:var(--pcd)!important;border:1px solid rgba(16,1,239,.15)!important}
#pcd .cta-d:hover{background:var(--pcd)!important;color:#fff!important}
#pcd .cta-a{background:var(--pcd)!important;color:#fff!important}
#pcd .cta-a:hover{background:var(--pcd-dk)!important}
#pcd .mc .cta-d{background:var(--pcd-or-lt)!important;color:#CC4400!important;border:1px solid var(--pcd-or-bd)!important}
#pcd .mc .cta-d:hover{background:var(--pcd-or)!important;color:#fff!important}
#pcd .mc .cta-a{background:var(--pcd-or)!important}
#pcd .mc .cta-a:hover{background:#CC4400!important}
/* Video: full width inside card, smooth expand */

#pcd .vp{width:100%;flex-basis:100%;max-height:0;overflow:hidden;border-radius:10px;transition:max-height .4s ease,margin .4s ease;margin:0}
#pcd .vp.open{max-height:280px;margin-top:10px}
#pcd .vp iframe{width:100%;height:260px;display:block;border:none!important;border-radius:10px}

#pcd .sb-tabs{display:flex;gap:0;margin:0 0 20px;border-radius:12px;overflow:hidden;border:2px solid #1001EF}
#pcd .sb-tab{flex:1;padding:14px 20px;text-align:center;font-size:15px!important;font-weight:700!important;cursor:pointer;transition:all .2s;background:#fff;color:#1001EF}
#pcd .sb-tab.active{background:#1001EF;color:#fff}
#pcd .sb-tab:hover:not(.active){background:#f0f0ff}
#pcd .sb-panel{display:none}
#pcd .sb-panel.active{display:block}
#pcd .T{position:fixed;top:20px;right:20px;background:var(--pcd-ok)!important;color:#fff!important;padding:12px 20px;border-radius:10px;font-weight:600!important;font-size:13px!important;box-shadow:0 8px 30px rgba(16,185,129,.4)!important;z-index:100000;display:none}
#pcd .T.on{display:block;animation:pSI .4s}
@keyframes pSI{from{opacity:0;transform:translateX(40px)}to{opacity:1;transform:translateX(0)}}
#pcd .AP{max-width:900px;margin:30px auto 0;padding:0 24px 40px;display:none}
#pcd .AP.on{display:block}
#pcd .AC{background:#fff;border:1px solid var(--pcd-bd)!important;border-radius:var(--pcd-r);padding:20px}
#pcd .AC h3{font-size:13px!important;font-weight:700!important;color:var(--pcd)!important;margin-bottom:2px!important}
#pcd .AC .as{font-size:11px!important;color:var(--pcd-txl)!important;margin-bottom:14px!important}
#pcd .tb{width:100%;border-collapse:collapse;font-size:11px!important}
#pcd .tb th{text-align:left;padding:6px;border-bottom:2px solid var(--pcd-bd)!important;font-weight:600!important;color:var(--pcd-txm)!important;font-size:9px!important;text-transform:uppercase;background:none!important}
#pcd .tb td{padding:7px 6px;border-bottom:1px solid #F0F0F5!important;color:var(--pcd-tx)!important;background:none!important}
#pcd .tb tr:last-child td{border-bottom:none!important}
#pcd .bx{margin-top:12px;padding:8px 16px;border-radius:7px;font-family:'DM Sans',sans-serif!important;font-size:11px!important;font-weight:600!important;cursor:pointer;display:inline-block}
#pcd .bx-b{border:1.5px solid var(--pcd)!important;background:#fff!important;color:var(--pcd)!important;margin-right:6px}
#pcd .bx-b:hover{background:var(--pcd)!important;color:#fff!important}
#pcd .bx-g{border:1.5px solid #555!important;background:#fff!important;color:#555!important;margin-right:6px}
#pcd .bx-g:hover{background:#555!important;color:#fff!important}
#pcd .bx-r{border:1.5px solid #E55!important;background:#fff!important;color:#E55!important}
#pcd .bx-r:hover{background:#E55!important;color:#fff!important}
#pcd .cb{display:inline-block;background:var(--pcd-lt);color:var(--pcd)!important;font-size:10px!important;font-weight:700!important;padding:2px 8px;border-radius:20px;margin-left:5px}



@keyframes pSH{0%,100%{transform:translateX(0)}20%{transform:translateX(-6px)}40%{transform:translateX(6px)}60%{transform:translateX(-4px)}80%{transform:translateX(4px)}}
@media(max-width:1024px){
  #pcd .H{min-height:320px}
  #pcd .Ht h1{font-size:26px!important}
  #pcd .Ht p{font-size:12px!important}
}
@media(max-width:600px){
  #pcd .H{min-height:220px}
  #pcd .Hi{flex-wrap:wrap;padding:16px;gap:12px}
  #pcd .Ht h1{font-size:20px!important}
  #pcd .Ht p{font-size:11px!important}
  #pcd .ac{padding:12px 10px;gap:8px}
  #pcd .an{display:none}
  #pcd .fc{padding:24px 18px}
  #pcd .fr{flex-direction:column;gap:0}
  #pcd .fcard .farrow{display:none}
#pcd .vp.open{max-height:200px}
#pcd .vp iframe{height:180px}
}

#pcd .cat{display:flex;align-items:center;gap:8px;padding:18px 0 8px;font-size:11px!important;font-weight:700!important;text-transform:uppercase;letter-spacing:1px;color:var(--pcd)!important}
#pcd .cat::after{content:'';flex:1;height:1.5px;background:linear-gradient(90deg,var(--pcd-bd),transparent)}
#pcd .cat .cat-icon{font-size:14px;font-style:normal!important}
#pcd .guide-back{display:inline-flex;align-items:center;gap:4px;font-size:12px!important;font-weight:600!important;color:var(--pcd)!important;cursor:pointer;padding:16px 0 8px;text-decoration:none!important}
#pcd .guide-back:hover{color:var(--pcd-dk)!important}

#pcd .coffee{display:inline-flex;align-items:center;gap:6px;background:linear-gradient(135deg,#FF813F,#FF6B35);color:#fff!important;font-size:12px!important;font-weight:600!important;padding:8px 16px;border-radius:8px;text-decoration:none!important;margin-top:12px;box-shadow:0 4px 12px rgba(255,107,53,.3)}
#pcd .pc-cta{display:inline-flex;align-items:center;gap:4px;background:#00f7ad;color:#001028!important;border:none!important;padding:6px 14px;font-size:9px!important;font-weight:700!important;border-radius:6px;text-decoration:none!important}
#pcd .pc-thx{opacity:.8;font-size:7.5px!important;color:rgba(255,255,255,.7)!important}

#pcd .coffee:hover{transform:translateY(-1px);box-shadow:0 6px 20px rgba(255,107,53,.4)!important}


/* ── PRINT STYLES ── */

#pcd.spline-full{position:relative}
#pcd.spline-full>.H{position:fixed;inset:0;min-height:100vh!important;z-index:0}
#pcd.spline-full .land,#pcd.spline-full .guide,#pcd.spline-full .AP{position:relative;z-index:1}
#pcd.spline-full .fcard,#pcd.spline-full .ac,#pcd.spline-full .AC,#pcd.spline-full .fc{background:rgba(255,255,255,.92)!important;backdrop-filter:blur(12px)!important;-webkit-backdrop-filter:blur(12px)!important}
#pcd.spline-full .fo{z-index:99999}
#pcd .pc-li{width:28px!important;height:28px!important;border-radius:50%!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;font-weight:700!important;font-size:12px!important;font-family:serif!important;padding:0!important;text-align:center!important}
#pcd .print-contact{display:none}

#pcd .print-hdr{display:none}

#pcd .print-footer{display:none}
@media print{
  @page{size:A4;margin:0;@bottom-center{content:counter(page)" / "counter(pages);font-family:"DM Sans",sans-serif;font-size:7pt;color:#bbb}}
  *{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  html,body{overflow:visible!important;width:100%!important;height:auto!important}
  ::-webkit-scrollbar{display:none!important}
  header:not(.H),footer:not(.print-footer),nav,.site-header,.site-footer,.site-navigation,.wp-block-navigation,.menu-toggle,#header-menu-toggle,.entry-footer,.post-navigation,.sidebar,#wpadminbar,.cookie-notice,.popup-overlay{display:none!important}
  #pcd{background:#fff!important;font-size:14px!important;width:100%!important;max-width:100%!important;margin:0!important;padding:0!important;float:none!important;position:static!important;overflow:visible!important}
  #pcd *{box-shadow:none!important;text-shadow:none!important;float:none!important}
  #pcd .H,#pcd .fo,#pcd .T,.bx,#pcd .AP,#pcd .guide-back,#pcd .vp,#pcd .sb-tabs{display:none!important}
  #pcd .land{display:none!important}
  #pcd .sb-panel{display:block!important}
  /* ── PRINT HEADER: full width gradient ── */
  #pcd .print-hdr{display:block!important;position:relative;width:100%;height:110px;overflow:hidden;margin:0 0 12px;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  #pcd .ph-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
  #pcd .ph-over{position:relative;z-index:1;display:flex!important;align-items:center;gap:14px;padding:20px 28px;height:100%}
  #pcd .ph-logo{width:48px;height:48px;border-radius:10px;object-fit:contain;padding:0;filter:brightness(0) invert(1)}
  #pcd .ph-title{color:#fff!important;font-size:20px!important;font-weight:700!important}
  #pcd .ph-sub{color:rgba(255,255,255,.85)!important;font-size:11px!important;margin-top:2px}
  /* ── GUIDES ── */
  #pcd .land{max-width:100%!important;padding:12px 20px!important}
  #pcd .fcard{break-inside:avoid;border:1px solid #ddd!important;margin-bottom:8px!important}
  #pcd .Lp,#pcd .Ll{display:none!important}
  #pcd .guide.on,[id="pcd-guide-os"][style*="block"],[id="pcd-guide-sb"][style*="block"]{display:block!important;max-width:100%!important;padding:0 20px!important}
  /* ── CARDS ── */
  #pcd .ac{break-inside:avoid;box-shadow:none!important;border:1px solid #E0E0EC!important;border-radius:10px!important;margin-bottom:6px!important;padding:12px 14px!important;background:#fff!important;display:flex!important;gap:10px!important}
  #pcd .ac:hover{transform:none!important}
  #pcd .mc{background:#FFF3ED!important;border:1.5px solid #FFD0B5!important}
  #pcd .an{width:18px!important;font-size:11px!important;padding-top:8px!important}
  #pcd .ai{width:38px!important;height:38px!important;min-width:38px!important;border-radius:10px!important;display:flex!important;align-items:center!important;justify-content:center!important;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  #pcd .ai img{width:26px!important;height:26px!important}
  #pcd .ab{flex:1!important;min-width:0!important}
  #pcd .nm{font-size:13px!important;font-weight:700!important;color:#1A1A2E!important}
  #pcd .mc .nm{color:#B83800!important}
  #pcd .pl{font-size:8px!important}
  #pcd .ad{font-size:10.5px!important;color:#4A4A66!important;line-height:1.4!important;margin-bottom:5px!important}
  #pcd .tg{font-size:8.5px!important;display:inline-block!important;padding:2px 7px!important;border-radius:4px!important;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  #pcd .af{display:flex!important;justify-content:space-between!important;align-items:center!important}
  #pcd .ctas{display:flex!important;gap:5px!important}
  #pcd .cta-d{display:inline-flex!important;font-size:8.5px!important;padding:3px 8px!important;border:1px solid #ddd!important;border-radius:5px!important;color:#555!important;background:#fff!important}
  #pcd .cta-a{display:inline-flex!important;font-size:8.5px!important;padding:3px 10px!important;background:#1001EF!important;color:#fff!important;border-radius:5px!important;text-decoration:none!important;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  /* ── CATEGORIES ── */
  #pcd .cat,#pcd .sl,#pcd .st{break-after:avoid;padding-top:14px!important;display:flex!important;font-size:10px!important}
  #pcd .cat::after,#pcd .sl::after,#pcd .st::after{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  /* ── CONTACT BANNER: full width ── */
  /* Contact banner (last page, full width, mirrors header) */
  #pcd .print-contact{display:block!important;break-inside:avoid;margin:20px 0 0;width:100%;position:relative;page-break-before:auto;overflow:hidden;z-index:999;page-break-inside:avoid;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  #pcd .pc-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
  #pcd .pc-inner{position:relative;z-index:1;background:rgba(26,26,46,.48)!important;padding:22px 28px 22px 32px!important;margin-bottom:-2mm;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important;border-radius:0!important;padding:20px 28px;color:#fff!important;display:flex!important;align-items:center;gap:16px}
  #pcd .pc-logo{width:64px;height:64px;flex-shrink:0;border-radius:10px;overflow:hidden;border:none;display:block;text-decoration:none}
  #pcd .pc-logo img{width:100%;height:100%;object-fit:contain;filter:brightness(0) invert(1)}
  #pcd .pc-info{flex:1}
  #pcd .pc-name{font-size:13px!important;font-weight:700!important;color:#fff!important}
  #pcd .pc-role{font-size:9px!important;color:#99AABB!important;margin-top:2px!important}
  #pcd .pc-phrase{font-size:8.5px!important;color:#00f7ad!important;font-style:italic!important;margin-top:5px!important}
  #pcd .pc-links{display:flex!important;gap:6px;flex-wrap:wrap;margin-top:8px}
  #pcd .pc-links a{color:#fff!important;font-size:8px!important;max-width:200px!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;padding:3px 10px;background:rgba(255,255,255,.1)!important;border:1px solid rgba(255,255,255,.2)!important;border-radius:5px;text-decoration:none!important;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  #pcd .pc-coffee{background:rgba(0,247,173,.15)!important;color:#00f7ad!important;border-color:rgba(0,247,173,.3)!important}
  
  /* ── FOOTER: full width, stuck at bottom ── */
  /* Page footer (repeats every page) */
  #pcd .print-footer{display:block!important;position:fixed;bottom:5mm;left:0;right:0;text-align:center;font-family:'DM Sans',sans-serif;font-size:6.5pt;color:#888;border-top:1.5px solid #1001EF!important;padding:6px 20px 0;margin:0;background:#fff!important;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
  #pcd .pf-b{color:#1001EF;font-weight:700;font-size:7.5pt}
  #pcd .pf-i{font-size:6.5pt;color:#aaa;margin-top:1px}
  /* ── LINKS ── */
  #pcd .eml{font-size:8px!important;display:inline!important}
  #pcd .pc-links .eml{font-size:8px!important}
  #pcd a{color:#1001EF!important}
  #pcd a[href]:after{content:none!important}
  #pcd .cta-a[href]:after,#pcd .cta-d[href]:after{content:none!important}
}

@media(max-width:600px){
  #pcd .tb{font-size:9px!important;display:block;overflow-x:auto;white-space:nowrap}
  #pcd .tb th,#pcd .tb td{padding:4px 3px!important;font-size:8px!important}
  #pcd .AC{padding:12px!important;overflow-x:auto}
  #pcd .cta-a,#pcd .cta-d{font-size:9px!important;padding:3px 6px!important}
  #pcd .af{flex-direction:column;align-items:flex-start!important;gap:6px!important}
}

</style></head><body><div id="pcd">

<!-- ╔═══════════════════════════════════════════════════════════════╗
     ║  🔧 CONFIG — TOUT SE MODIFIE ICI                            ║
     ╚═══════════════════════════════════════════════════════════════╝ -->
<script>
var C={
  LOGO_PCD:"https://presentcomposedesign.fr/wp-content/uploads/2024/03/cropped-logo_PCd_2024.png",
  LOGO_PCD_ON_SCREEN:false,  // true = visible à l'écran, false = print seulement

  LOGO_LIEU:"https://presentcomposedesign.fr/wp-content/uploads/2026/03/Logo_studio_m_wiki.png",
  LOGO_LIEU_ON_SCREEN:false, // true = visible à l'écran, false = print seulement

  TITRE:"Formations",
  CREDIT:"Présent Composé Design / Alban Desbarax",
  FAVICON:"https://presentcomposedesign.fr/wp-content/uploads/2024/03/cropped-logo_PCd_2024-32x32.png",
  SPLINE:"https://prod.spline.design/SsCdd-1WulmAbnAK/scene.splinecode",
  SPLINE_MODE:"header", // "header" | "fullscreen" | "header-footer"

  /* ── VIDEOS DEMO YOUTUBE ─────────────────────────────────────
   *  id = ID YouTube (ex: "UIZAiXYceBI"). Autoplay muet au hover.
   *       Clic sur la carte = active le son.
   *       Clic "▶ Demo" = ouvre YouTube plein écran avec son.
   *  q  = recherche YouTube (fallback si id est vide)
   *
   *  ▶ POUR TROUVER UN ID : ouvrir TROUVER_LES_IDS_YOUTUBE.html
   *    L'ID est le code après "v=" dans youtube.com/watch?v=XXXXX
   * ────────────────────────────────────────────────────────── */
  VIDEOS:{
    mistral: {id:"",q:"Mistral AI Le Chat demo tutoriel"},
    chatgpt: {id:"",q:"ChatGPT DALL-E image generation demo 2025"},
    gemini:  {id:"UIZAiXYceBI",q:"Google Gemini Veo 3 video demo"},
    canva:   {id:"",q:"Canva AI image video generator demo"},
    firefly: {id:"Sp6K3qpVFO0",q:"Adobe Firefly demo tutorial"},
    luma:    {id:"",q:"Luma AI Dream Machine video demo"},
    runway:  {id:"",q:"Runway Gen-4 AI video demo"},
    leonardo:{id:"",q:"Leonardo AI image generation tutorial"},
    ideogram:{id:"",q:"Ideogram AI text image demo"},
    copilot: {id:"S7xTBa93TX8",q:"Microsoft Copilot image generator demo"},
    pika:    {id:"",q:"Pika AI video generation demo"}
  }
};
document.addEventListener('DOMContentLoaded',function(){
  var lp=document.getElementById('pcd-lp'),ll=document.getElementById('pcd-ll');
  lp.querySelector('img').src=C.LOGO_PCD;
  ll.querySelector('img').src=C.LOGO_LIEU;
  if(C.LOGO_PCD_ON_SCREEN) lp.classList.add('show-screen');
  if(C.LOGO_LIEU_ON_SCREEN) ll.classList.add('show-screen');
  document.getElementById('pcd-t').textContent=C.TITRE;
  document.getElementById('pcd-c').textContent=C.CREDIT;
  var f=document.querySelector('link[rel="icon"]');if(f)f.href=C.FAVICON;
  document.getElementById('pcd-spline').setAttribute('url',C.SPLINE);

/* Apply Spline mode */
if(C.SPLINE_MODE==='fullscreen'){document.getElementById('pcd').classList.add('spline-full')}

});
</script>

<div class="T" id="pcd-toast">✓ Guide débloqué !</div>
<div class="fo" id="pcd-fo"><div class="fc"><div class="fcl" onclick="document.getElementById('pcd-fo').classList.remove('on')">✕</div><div class="fb" id="pcd-fo-badge">🎨 Formation Découverte IA</div><h2 id="pcd-fo-title">Débloquez le guide</h2><p class="fs" id="pcd-fo-desc">Entrez vos coordonnées pour accéder au <strong>guide sélectionné</strong>.</p><div class="fr"><div class="fg"><label>Prénom</label><input type="text" id="pcd-fn" placeholder="Votre prénom"></div><div class="fg"><label>Nom</label><input type="text" id="pcd-ln" placeholder="Votre nom"></div></div><div class="fg"><label>Email</label><input type="email" id="pcd-em" placeholder="votre@email.com"></div><div class="fg"><label>Téléphone <span class="op">(optionnel)</span></label><input type="tel" id="pcd-ph" placeholder="06 12 34 56 78"></div><div class="fg"><label>Vous êtes</label><select id="pcd-pr" onchange="var f=document.getElementById('pcd-sf');this.value==='pro_autre'?f.classList.add('v'):f.classList.remove('v')"><option value="">· Choisissez ·</option><option value="etudiant">Étudiant·e</option><option value="pro_design">Pro du design / créatif</option><option value="pro_autre">Pro (autre secteur)</option><option value="entrepreneur">Entrepreneur·e</option><option value="curieux">Curieux·se / Découverte</option></select></div><div class="fg sf" id="pcd-sf"><label>Secteur d'activité</label><input type="text" id="pcd-sc" placeholder="Ex : architecture, santé…"></div><div class="fg"><label>Code d'accès <span class="op">(fourni par le formateur)</span></label><input type="text" id="pcd-code" placeholder="1 2 3 4" maxlength="4" onkeydown="if(event.key==='Enter')pSub()" style="text-transform:uppercase;letter-spacing:4px;font-family:'Space Mono',monospace!important;font-size:18px!important;text-align:center"></div><button class="btn" id="pcd-sub" onclick="pSub()">Accéder au guide →</button><p class="fn">🔒 Données utilisées uniquement pour cette formation.</p></div></div>

<header class="H"><spline-viewer id="pcd-spline" loading="lazy" events-target="none"></spline-viewer><div class="Hi"><div class="Hl"><div class="Lp" id="pcd-lp"><img alt="PCD"></div><div class="Ht"><h1 id="pcd-t">Formations</h1><p id="pcd-c">Présent Composé Design / Alban Desbarax</p></div></div><div class="Ll" id="pcd-ll"><img alt=""></div></div></header>

<script>
var currentGuide='ia';
function openForm(g){
  currentGuide=g;
  var fo=document.getElementById('pcd-fo');
  var badge=document.getElementById('pcd-fo-badge');
  var title=document.getElementById('pcd-fo-title');
  var desc=document.getElementById('pcd-fo-desc');
  if(g==='ia'){
    badge.textContent='\u{1F3A8} Formation D\u00e9couverte IA';
    title.textContent='D\u00e9bloquez le guide IA';
    desc.innerHTML='Entrez vos coordonn\u00e9es pour acc\u00e9der au <strong>Top 10 des apps IA gratuites</strong>.';
  }else if(g==='sb'){
    badge.textContent='\u{1F3AC} Storyboard & virtual production IA TOOLBOX';
    title.textContent='D\u00e9bloquez la toolbox';
    desc.innerHTML='Acc\u00e9dez aux <strong>20 outils IA + 100 termes</strong> du storyboarder.';
  }else{
    badge.textContent='\u{1F4BB} Applications Open Source';
    title.textContent='D\u00e9bloquez le guide';
    desc.innerHTML='Entrez vos coordonn\u00e9es pour acc\u00e9der au <strong>Top 25 des logiciels open source</strong>.';
  }
  fo.classList.add('on');
}
function showLanding(){
  document.getElementById('pcd-guide').classList.remove('on');
  var os=document.getElementById('pcd-guide-os');if(os)os.style.display='none';
  var sb=document.getElementById('pcd-guide-sb');if(sb)sb.style.display='none';

  document.getElementById('pcd-land').style.display='block';
}


/* Fix Demo buttons: set real hrefs for PDF print */
document.querySelectorAll('#pcd-guide .cta-d').forEach(function(btn){
  var card=btn.closest('.ac[data-v]');
  if(!card)return;
  var key=card.getAttribute('data-v');
  var v=C.VIDEOS[key];
  if(!v)return;
  if(v.id){btn.href='https://www.youtube.com/watch?v='+v.id}
  else{btn.href='https://www.youtube.com/results?search_query='+encodeURIComponent(v.q)}
  btn.setAttribute('target','_blank');
});
/* OS guide Demo buttons already have real hrefs */

/* Video hover: autoplay for all cards */
document.querySelectorAll('.ac[data-v]').forEach(function(card){
  var key=card.getAttribute('data-v'),vp=card.querySelector('.vp');
  if(!vp)return;
  var v=C.VIDEOS?C.VIDEOS[key]:null;
  var demoBtn=card.querySelector('.cta-d');
  var demoHref=demoBtn?demoBtn.getAttribute('href'):'';
  var vid='';
  if(v&&v.id){vid=v.id}
  else if(demoHref){var m=demoHref.match(/watch\?v=([^&]+)/);if(m)vid=m[1]}
  var searchQ=(v&&v.q)?v.q:'';
  if(!searchQ&&demoHref){var sq=demoHref.match(/search_query=([^&]+)/);if(sq)searchQ=decodeURIComponent(sq[1]).replace(/\+/g,' ')}
  if(!vid)return;
  var timer=null;
  card.addEventListener('mouseenter',function(){
    timer=setTimeout(function(){
      var src='https://www.youtube.com/embed/'+vid+'?autoplay=1&mute=1&rel=0&modestbranding=1&controls=0';
      vp.innerHTML='<iframe src="'+src+'" allow="autoplay;encrypted-media" allowfullscreen loading="lazy"></iframe>';
      vp.classList.add('open');
    },300);
  });
  card.addEventListener('mouseleave',function(){
    clearTimeout(timer);
    vp.classList.remove('open');
    setTimeout(function(){vp.innerHTML=''},400);
  });
});
document.querySelectorAll('.eml').forEach(function(el){el.textContent=String.fromCharCode(99,111,110,116,97,99,116,64,112,114,101,115,101,110,116,99,111,109,112,111,115,101,100,101,115,105,103,110,46,102,114)});
</script>

<div class="print-hdr" id="pcd-print-hdr">
<img decoding="async" src="https://presentcomposedesign.fr/wp-content/uploads/2026/03/abstract-gradient-background-Formation-page@1-2048x1111abstract-gradient-background-Formation_PresentComposedesign_header.png" class="ph-bg" alt="">
<div class="ph-over">
<a href="https://presentcomposedesign.fr" target="_blank"><img decoding="async" src="https://presentcomposedesign.fr/wp-content/uploads/2025/07/Present-Compose-design_logo-image.svg" class="ph-logo" alt="PCD"></a>
<div class="ph-text">
<div class="ph-title">Formations</div>
<div class="ph-sub">Présent Composé Design / Alban Desbarax</div>
</div>
</div>
</div>
<section class="land" id="pcd-land"><div class="land-title">Ateliers & Ressources</div><div class="fcard" onclick="openForm('ia')"><h2>🎨 TOP 10 Applications IA Génératives 2026</h2><p class="fdesc">Les meilleures apps gratuites (téléphone & desktop) pour générer des images et vidéos facilement avec l'IA. Guide interactif avec démos vidéo.</p><span class="fbadge">GRATUIT · Guide interactif · 11 apps testées</span><div class="farrow"><svg viewBox="0 0 16 16"><path d="M5 11L11 5M11 5H6M11 5V10"/></svg></div></div><div class="fcard" onclick="openForm('os')" style="margin-top:12px"><h2>💻 TOP 25 Applications Open Source à installer en 2026</h2><p class="fdesc">La sélection essentielle des logiciels gratuits & open source pour la création 3D, audio, vidéo, design, impression 3D, code créatif et productivité.</p><span class="fbadge">GRATUIT · 25 logiciels · 7 catégories · Liens de téléchargement</span><div class="farrow"><svg viewBox="0 0 16 16"><path d="M5 11L11 5M11 5H6M11 5V10"/></svg></div></div><div class="fcard" onclick="openForm('sb')" style="margin-top:12px"><h2>🎬 Storyboard &amp; virtual production IA TOOLBOX</h2><p class="fdesc">20 outils IA et 100 termes techniques pour la création de storyboards. Glossaire interactif, prompts prêts à l'emploi, liens et demos.</p><span class="fbadge">GRATUIT · 20 outils · 100 termes · 2 onglets</span><div class="farrow"><svg viewBox="0 0 16 16"><path d="M5 11L11 5M11 5H6M11 5V10"/></svg></div></div></section>

<section class="guide" id="pcd-guide">
<div class="guide-back" onclick="showLanding()">← Retour aux formations</div>
<div class="sl">★ Incontournable / Assistant IA quotidien</div>
<div class="ac mc" data-v="mistral"><div class="an">★</div><div class="ai" style="background:linear-gradient(135deg,#FF6B35,#FF8F5E);"><img decoding="async" src="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64" alt="" onerror="this.style.display='none';this.parentElement.textContent='M'"></div><div class="ab"><div class="ah"><span class="nm">Mistral AI (Le Chat)</span><span class="pl">Web · iOS · Android</span></div><p class="ad">Assistant IA français polyvalent : texte, recherche, résumé, analyse. Idéal pour la productivité quotidienne.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF3ED;color:#CC4400;">Texte</span><span class="tg" style="background:#FFF3ED;color:#CC4400;">Recherche</span><span class="tg" style="background:#FFF3ED;color:#CC4400;">Analyse</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Mistral+AI+Le+Chat+demo+tutoriel" target="_blank">▶ Demo</a><a class="cta-a" href="https://chat.mistral.ai" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🖼️</span> Images / Génération & édition</div>
<div class="ac" data-v="chatgpt"><div class="an">1</div><div class="ai" style="background:#E6F7F1;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=chatgpt.com&sz=64" alt="" onerror="this.parentElement.style.background='#10A37F';this.parentElement.textContent='G';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">ChatGPT + DALL·E</span><span class="pl">Web · iOS · Android</span></div><p class="ad">Génération d'images réalistes via GPT-4o. ~3 images/jour en gratuit. Texte lisible dans les images.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Images</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Texte</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=ChatGPT+DALL-E+image+generation+demo+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://chatgpt.com" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="gemini"><div class="an">2</div><div class="ai" style="background:#E8F0FE;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=gemini.google.com&sz=64" alt="" onerror="this.parentElement.style.background='#4285F4';this.parentElement.textContent='G';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Google Gemini + Veo 3.1</span><span class="pl">Web · iOS · Android</span></div><p class="ad">IA multimodale Google. Images (Nano Banana) et vidéos HD avec audio natif via Flow. Gratuit et puissant.</p><div class="af"><div class="at"><span class="tg" style="background:#E8F0FE;color:#1A73E8;">Images</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;">Vidéos</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;">Audio</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/watch?v=UIZAiXYceBI" target="_blank">▶ Demo</a><a class="cta-a" href="https://gemini.google.com" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="canva"><div class="an">3</div><div class="ai" style="background:#E5F9FA;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=canva.com&sz=64" alt="" onerror="this.parentElement.style.background='#00C4CC';this.parentElement.textContent='C';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Canva IA</span><span class="pl">Web · iOS · Android</span></div><p class="ad">Suite de design avec images (Média Magique) et vidéos IA (Veo-3). Intuitive, idéale pour débutants.</p><div class="af"><div class="at"><span class="tg" style="background:#E5F9FA;color:#00A5AB;">Images</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;">Vidéos</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;">Design</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Canva+AI+image+video+generator+demo" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.canva.com" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="firefly"><div class="an">4</div><div class="ai" style="background:#FFF0EB;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=firefly.adobe.com&sz=64" alt="" onerror="this.parentElement.style.background='#FF4500';this.parentElement.textContent='A';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Adobe Firefly</span><span class="pl">Web · Desktop</span></div><p class="ad">Générateur images/vidéos premium d'Adobe. 25 crédits gratuits/mois. Remplissage génératif et retouche.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF0EB;color:#CC3700;">Images</span><span class="tg" style="background:#FFF0EB;color:#CC3700;">Vidéos</span><span class="tg" style="background:#FFF0EB;color:#CC3700;">Retouche</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/watch?v=Sp6K3qpVFO0" target="_blank">▶ Demo</a><a class="cta-a" href="https://firefly.adobe.com" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🎬</span> Vidéos / Génération & animation</div>
<div class="ac" data-v="luma"><div class="an">5</div><div class="ai" style="background:#F0EAFF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=lumalabs.ai&sz=64" alt="" onerror="this.parentElement.style.background='#7C3AED';this.parentElement.textContent='L';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Luma AI (Dream Machine)</span><span class="pl">Web · iOS · Android</span></div><p class="ad">Génération vidéo réaliste à partir de texte ou d'images. Capture 3D photoréaliste avec téléphone.</p><div class="af"><div class="at"><span class="tg" style="background:#F0EAFF;color:#6D28D9;">Vidéos</span><span class="tg" style="background:#F0EAFF;color:#6D28D9;">3D</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Luma+AI+Dream+Machine+video+demo" target="_blank">▶ Demo</a><a class="cta-a" href="https://lumalabs.ai" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="runway"><div class="an">6</div><div class="ai" style="background:#E6F0FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=runwayml.com&sz=64" alt="" onerror="this.parentElement.style.background='#0066FF';this.parentElement.textContent='R';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Runway (Gen-4)</span><span class="pl">Web · iOS</span></div><p class="ad">Outil cinématographique. Vidéo à partir de texte, images ou clips. Productions réelles.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F0FF;color:#0052CC;">Vidéos</span><span class="tg" style="background:#E6F0FF;color:#0052CC;">Cinéma</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Runway+Gen-4+AI+video+demo" target="_blank">▶ Demo</a><a class="cta-a" href="https://runwayml.com" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="leonardo"><div class="an">7</div><div class="ai" style="background:#F0EAFF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=leonardo.ai&sz=64" alt="" onerror="this.parentElement.style.background='#8B5CF6';this.parentElement.textContent='L';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Leonardo AI</span><span class="pl">Web · iOS · Android</span></div><p class="ad">Générateur d'images avec nombreux modèles. 150 tokens/jour gratuits. Assets visuels.</p><div class="af"><div class="at"><span class="tg" style="background:#F0EAFF;color:#7C3AED;">Images</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;">Assets</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Leonardo+AI+image+generation+tutorial" target="_blank">▶ Demo</a><a class="cta-a" href="https://leonardo.ai" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="ideogram"><div class="an">8</div><div class="ai" style="background:#FFF0F3;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=ideogram.ai&sz=64" alt="" onerror="this.parentElement.style.background='#E11D48';this.parentElement.textContent='I';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Ideogram</span><span class="pl">Web · iOS · Android</span></div><p class="ad">Maîtrise du texte dans les images. ~40 images/semaine gratuits. Résultats créatifs.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF0F3;color:#BE123C;">Images</span><span class="tg" style="background:#FFF0F3;color:#BE123C;">Typographie</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Ideogram+AI+text+image+demo" target="_blank">▶ Demo</a><a class="cta-a" href="https://ideogram.ai" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="copilot"><div class="an">9</div><div class="ai" style="background:#E6F2FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=copilot.microsoft.com&sz=64" alt="" onerror="this.parentElement.style.background='#0078D4';this.parentElement.textContent='C';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Microsoft Copilot</span><span class="pl">Web · iOS · Android</span></div><p class="ad">DALL·E 3 gratuit et illimité via Microsoft. Aucune inscription nécessaire.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F2FF;color:#005EA6;">Images</span><span class="tg" style="background:#E6F2FF;color:#005EA6;">Illimité</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/watch?v=S7xTBa93TX8" target="_blank">▶ Demo</a><a class="cta-a" href="https://copilot.microsoft.com" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="pika"><div class="an">10</div><div class="ai" style="background:#FEF3C7;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=pika.art&sz=64" alt="" onerror="this.parentElement.style.background='#F59E0B';this.parentElement.textContent='P';this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Pika</span><span class="pl">Web · iOS</span></div><p class="ad">Vidéos courtes créatives pour réseaux sociaux. Interface simple.</p><div class="af"><div class="at"><span class="tg" style="background:#FEF3C7;color:#D97706;">Vidéos</span><span class="tg" style="background:#FEF3C7;color:#D97706;">Social</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Pika+AI+video+generation+demo" target="_blank">▶ Demo</a><a class="cta-a" href="https://pika.art" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>
</section>


<section class="guide" id="pcd-guide-os" style="display:none">
<div class="guide-back" onclick="showLanding()">← Retour aux formations</div>
<div class="sl">💻 TOP 25 Applications Open Source & Gratuites · PC 2026</div>
<div class="cat"><span class="cat-icon">🎮</span> 3D · Moteurs · VR / XR</div>
<div class="ac" data-v="blender.org"><div class="ai" style="background:#E8E5FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=blender.org&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Blender</span></div><p class="ad">Suite 3D complète : modélisation, animation, rendu, compositing. Le standard open source.</p><div class="af"><div class="at"><span class="tg" style="background:#E8E5FF;color:#1001EF;">3D</span><span class="tg" style="background:#E8E5FF;color:#1001EF;">Animation</span><span class="tg" style="background:#E8E5FF;color:#1001EF;">Rendu</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Blender+3D+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.blender.org/download/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="roblox.com"><div class="ai" style="background:#E8E5FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=roblox.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Roblox Studio</span></div><p class="ad">Créez vos propres jeux et expériences 3D. Plateforme massive de création interactive.</p><div class="af"><div class="at"><span class="tg" style="background:#E8E5FF;color:#1001EF;">Jeux</span><span class="tg" style="background:#E8E5FF;color:#1001EF;">3D</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Roblox+Studio+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.roblox.com/create" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="unity.com"><div class="ai" style="background:#E8E5FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=unity.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Unity / Unreal Engine</span></div><p class="ad">Les deux moteurs de jeu de référence. Unity (C#) et Unreal (Blueprints/C++). Gratuits pour débuter.</p><div class="af"><div class="at"><span class="tg" style="background:#E8E5FF;color:#1001EF;">Jeux</span><span class="tg" style="background:#E8E5FF;color:#1001EF;">3D</span><span class="tg" style="background:#E8E5FF;color:#1001EF;">XR</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Unity+vs+Unreal+Engine+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://unity.com/download" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="babylonjs.com"><div class="ai" style="background:#E8E5FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=babylonjs.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Babylon.js</span></div><p class="ad">Moteur 3D web open source par Microsoft. Créez des expériences 3D/WebXR dans le navigateur.</p><div class="af"><div class="at"><span class="tg" style="background:#E8E5FF;color:#1001EF;">Web3D</span><span class="tg" style="background:#E8E5FF;color:#1001EF;">WebXR</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Babylon.js+tutorial+getting+started+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.babylonjs.com/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="sidequestvr.com"><div class="ai" style="background:#E8E5FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=sidequestvr.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">SideQuest</span></div><p class="ad">Plateforme de sideloading pour Meta Quest. Accédez à des apps VR non officielles.</p><div class="af"><div class="at"><span class="tg" style="background:#E8E5FF;color:#1001EF;">VR</span><span class="tg" style="background:#E8E5FF;color:#1001EF;">Quest</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=SideQuest+Meta+Quest+tutorial+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://sidequestvr.com/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🎵</span> Audio · Musique · Son</div>
<div class="ac" data-v="reaper.fm"><div class="ai" style="background:#FFF3ED;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=reaper.fm&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Reaper</span></div><p class="ad">DAW professionnel ultra-léger. Licence d'évaluation illimitée. Plugins VST, MIDI, multitrack.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF3ED;color:#CC4400;">DAW</span><span class="tg" style="background:#FFF3ED;color:#CC4400;">Audio</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Reaper+DAW+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.reaper.fm/download.php" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="ableton.com"><div class="ai" style="background:#FFF3ED;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=ableton.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Ableton Live Lite</span></div><p class="ad">DAW référence pour la musique électronique et le live. Version Lite gratuite avec instruments.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF3ED;color:#CC4400;">DAW</span><span class="tg" style="background:#FFF3ED;color:#CC4400;">Live</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Ableton+Live+Lite+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.ableton.com/en/products/live-lite/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="cycling74.com"><div class="ai" style="background:#FFF3ED;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=cycling74.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Max MSP</span></div><p class="ad">Environnement de programmation visuelle pour audio, MIDI, vidéo et médias interactifs.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF3ED;color:#CC4400;">Audio</span><span class="tg" style="background:#FFF3ED;color:#CC4400;">Visuel</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Max+MSP+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://cycling74.com/downloads" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🎬</span> Vidéo · Montage · Compositing</div>
<div class="ac" data-v="blackmagicdesign.com"><div class="ai" style="background:#E6F7F1;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=blackmagicdesign.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">DaVinci Resolve</span></div><p class="ad">Suite pro complète : montage, étalonnage, VFX, mixage audio. Gratuit et très puissant.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Montage</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">VFX</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Color</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=DaVinci+Resolve+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.blackmagicdesign.com/products/davinciresolve" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="capcut.com"><div class="ai" style="background:#E6F7F1;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=capcut.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">CapCut</span></div><p class="ad">Montage vidéo simple et efficace. Templates, effets, sous-titres auto. Idéal réseaux sociaux.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Montage</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Social</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=CapCut+tutorial+montage+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.capcut.com/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="natrongithub.github.io"><div class="ai" style="background:#E6F7F1;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=natrongithub.github.io&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Natron</span></div><p class="ad">Compositing node-based open source. Alternative à After Effects/Nuke pour le VFX.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">VFX</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Compositing</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Natron+compositing+tutorial+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://natrongithub.github.io/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="videolan.org"><div class="ai" style="background:#E6F7F1;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=videolan.org&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">VLC</span></div><p class="ad">Lecteur multimédia universel. Lit tous les formats, convertit, streame. Incontournable.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Lecteur</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;">Conversion</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=VLC+media+player+astuces+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.videolan.org/vlc/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🎨</span> Design · Image · UI</div>
<div class="ac" data-v="figma.com"><div class="ai" style="background:#F0EAFF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=figma.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Figma</span></div><p class="ad">Design d'interfaces, prototypage, collaboration temps réel. Version gratuite très généreuse.</p><div class="af"><div class="at"><span class="tg" style="background:#F0EAFF;color:#7C3AED;">UI/UX</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;">Prototypage</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Figma+tutorial+d%C3%A9butant+UI+design+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.figma.com/downloads/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="affinity.serif.com"><div class="ai" style="background:#F0EAFF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=affinity.serif.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Affinity</span></div><p class="ad">Suite créative (Photo, Designer, Publisher). Alternative premium à Adobe, licence perpétuelle.</p><div class="af"><div class="at"><span class="tg" style="background:#F0EAFF;color:#7C3AED;">Design</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;">Photo</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Affinity+Designer+Photo+tutorial+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://affinity.serif.com/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="xnview.com"><div class="ai" style="background:#F0EAFF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=xnview.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">XnView</span></div><p class="ad">Visionneuse et convertisseur d'images. Supporte 500+ formats. Batch processing puissant.</p><div class="af"><div class="at"><span class="tg" style="background:#F0EAFF;color:#7C3AED;">Images</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;">Batch</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=XnView+tutorial+batch+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.xnview.com/en/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🖨️</span> Impression 3D · Fabrication</div>
<div class="ac" data-v="bambulab.com"><div class="ai" style="background:#FEF3C7;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=bambulab.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Bambu Studio</span></div><p class="ad">Slicer officiel Bambu Lab. Profils optimisés, multi-couleur, interface moderne.</p><div class="af"><div class="at"><span class="tg" style="background:#FEF3C7;color:#D97706;">Slicer</span><span class="tg" style="background:#FEF3C7;color:#D97706;">FDM</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Bambu+Studio+slicer+tutorial+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://bambulab.com/en/download/studio" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="github.com"><div class="ai" style="background:#FEF3C7;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=github.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Orca Slicer</span></div><p class="ad">Fork communautaire de Bambu Studio. Compatible toutes imprimantes, très personnalisable.</p><div class="af"><div class="at"><span class="tg" style="background:#FEF3C7;color:#D97706;">Slicer</span><span class="tg" style="background:#FEF3C7;color:#D97706;">Open Source</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Orca+Slicer+tutorial+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://github.com/SoftFever/OrcaSlicer/releases" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="ultimaker.com"><div class="ai" style="background:#FEF3C7;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=ultimaker.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Cura (UltiMaker)</span></div><p class="ad">Slicer universel le plus utilisé au monde. Marketplace de plugins, profils communautaires.</p><div class="af"><div class="at"><span class="tg" style="background:#FEF3C7;color:#D97706;">Slicer</span><span class="tg" style="background:#FEF3C7;color:#D97706;">Universel</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Cura+slicer+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://ultimaker.com/software/ultimaker-cura/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">⚡</span> Code créatif · IA générative</div>
<div class="ac" data-v="derivative.ca"><div class="ai" style="background:#FFF0F3;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=derivative.ca&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">TouchDesigner</span></div><p class="ad">Programmation visuelle temps réel pour installations interactives, VJing, mapping.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF0F3;color:#BE123C;">Interactif</span><span class="tg" style="background:#FFF0F3;color:#BE123C;">Temps réel</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=TouchDesigner+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://derivative.ca/download" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="processing.org"><div class="ai" style="background:#FFF0F3;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=processing.org&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Processing</span></div><p class="ad">Langage de programmation créative. Idéal pour apprendre le code par le visuel.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF0F3;color:#BE123C;">Code</span><span class="tg" style="background:#FFF0F3;color:#BE123C;">Art</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Processing+creative+coding+tutorial+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://processing.org/download" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="arduino.cc"><div class="ai" style="background:#FFF0F3;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=arduino.cc&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Arduino</span></div><p class="ad">Plateforme électronique open source. IDE + cartes pour prototypage interactif.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF0F3;color:#BE123C;">Électronique</span><span class="tg" style="background:#FFF0F3;color:#BE123C;">IoT</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Arduino+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.arduino.cc/en/software" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="comfy.org"><div class="ai" style="background:#FFF0F3;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=comfy.org&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">ComfyUI</span></div><p class="ad">Interface node-based pour Stable Diffusion. Workflows visuels pour la génération d'images IA.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF0F3;color:#BE123C;">IA</span><span class="tg" style="background:#FFF0F3;color:#BE123C;">Stable Diffusion</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=ComfyUI+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://github.com/comfyanonymous/ComfyUI" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🔧</span> Outils · Productivité · Communication</div>
<div class="ac" data-v="code.visualstudio.com"><div class="ai" style="background:#E6F2FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=code.visualstudio.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Visual Studio Code</span></div><p class="ad">Éditeur de code le plus populaire. Extensions, Git, terminal intégré, IA (Copilot).</p><div class="af"><div class="at"><span class="tg" style="background:#E6F2FF;color:#005EA6;">Code</span><span class="tg" style="background:#E6F2FF;color:#005EA6;">IDE</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Visual+Studio+Code+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://code.visualstudio.com/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="openoffice.org"><div class="ai" style="background:#E6F2FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=openoffice.org&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">OpenOffice</span></div><p class="ad">Suite bureautique complète et gratuite. Writer, Calc, Impress. Alternative à Microsoft Office.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F2FF;color:#005EA6;">Bureau</span><span class="tg" style="background:#E6F2FF;color:#005EA6;">Docs</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=OpenOffice+tutorial+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.openoffice.org/download/" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>
<div class="ac" data-v="discord.com"><div class="ai" style="background:#E6F2FF;"><img decoding="async" src="https://www.google.com/s2/favicons?domain=discord.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Discord</span></div><p class="ad">Plateforme de communication. Salons vocaux/texte, partage d'écran, bots, communautés.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F2FF;color:#005EA6;">Chat</span><span class="tg" style="background:#E6F2FF;color:#005EA6;">Communauté</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Discord+tutorial+d%C3%A9butant+2025" target="_blank">▶ Demo</a><a class="cta-a" href="https://discord.com/download" target="_blank">Télécharger ↓</a></div></div></div><div class="vp"></div></div>

</section>






<section class="guide" id="pcd-guide-sb" style="display:none">
<div class="guide-back" onclick="showLanding()">← Retour aux formations</div>
<div class="sl">🎬 STORYBOARD & VIRTUAL PRODUCTION IA TOOLBOX</div>
<div class="sb-tabs">
<div class="sb-tab active" onclick="document.querySelectorAll('.sb-tab,.sb-panel').forEach(e=>e.classList.remove('active'));this.classList.add('active');document.getElementById('sb-outils').classList.add('active')">🛠 Outils (20)</div>
<div class="sb-tab" onclick="document.querySelectorAll('.sb-tab,.sb-panel').forEach(e=>e.classList.remove('active'));this.classList.add('active');document.getElementById('sb-glossaire').classList.add('active')">📖 Glossaire (100)</div>
</div>
<div class="sb-panel active" id="sb-outils">
<div class="cat"><span class="cat-icon">🖼️</span> Génération d'images</div>
<div class="ac" data-v="www.comfy.org"><div class="an">1</div><div class="ai" style="background:#E8F0FE"><img decoding="async" src="https://www.google.com/s2/favicons?domain=www.comfy.org&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">ComfyUI</span><span class="pl" style="background:#e8f5ed;color:#27ae60;padding:2px 6px;border-radius:3px;font-size:9px">Gratuit</span></div><p class="ad">Interface node-based pour Stable Diffusion et Flux. Workflows visuels puissants pour la génération d'images IA. Personnalisation totale, ControlNet, IP-Adapter, cohérence entre panels.</p><div class="af"><div class="at"><span class="tg" style="background:#E8F0FE;color:#1A73E8">Workflow visuel</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Stable Diffusion</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">ControlNet</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Cohérence</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=ComfyUI" target="_blank">▶ Demo</a><a class="cta-a" href="https://www.comfy.org/" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="ControlNet pose + IP-Adapter style: Generate storyboard panel, plan rapproché, dutch angle 15°, hard side lighting, clair-obscur, background defocused urban décor, cinematic 16:9, high contrast B&amp;W storyboard sketch style" title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>ControlNet pose + IP-Adapter style: Generate storyboard panel, plan rapproché, dutch angle 15°, hard side lighting, clair-obscur, background defocused urban déc...</div></div><div class="vp"></div></div>
<div class="ac" data-v="labs.google"><div class="an">2</div><div class="ai" style="background:#E8F0FE"><img decoding="async" src="https://www.google.com/s2/favicons?domain=labs.google&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Google Flow</span><span class="pl" style="background:#e8f5ed;color:#27ae60;padding:2px 6px;border-radius:3px;font-size:9px">Gratuit</span></div><p class="ad">Outil Google pour créer des storyboards et moodboards visuels avec l'IA. Génération d'images à partir de prompts textuels, idéal pour la pré-production et la visualisation rapide de concepts narratifs.</p><div class="af"><div class="at"><span class="tg" style="background:#E8F0FE;color:#1A73E8">Storyboard</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Moodboard</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Google AI</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Pré-production</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Google+Flow" target="_blank">▶ Demo</a><a class="cta-a" href="https://labs.google/flow/about" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Cinematic storyboard panel, establishing shot, rain-soaked alley at night, low key lighting, hard light from neon creating clair-obscur, foreground bokeh, deep depth of field, 2.39:1 cinémascope" title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Cinematic storyboard panel, establishing shot, rain-soaked alley at night, low key lighting, hard light from neon creating clair-obscur, foreground bokeh, deep ...</div></div><div class="vp"></div></div>
<div class="ac" data-v="stability.ai"><div class="an">3</div><div class="ai" style="background:#E8F0FE"><img decoding="async" src="https://www.google.com/s2/favicons?domain=stability.ai&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Stable Diffusion</span><span class="pl" style="background:#e8f5ed;color:#27ae60;padding:2px 6px;border-radius:3px;font-size:9px">Gratuit</span></div><p class="ad">Modèle open-source de génération d'images. Utilisable localement ou via ComfyUI. Parfait pour créer des planches cohérentes avec des LoRA personnalisés (personnages, univers visuels constants).</p><div class="af"><div class="at"><span class="tg" style="background:#E8F0FE;color:#1A73E8">Cohérence personnage</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Style graphique</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Batch génération</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Stable+Diffusion" target="_blank">▶ Demo</a><a class="cta-a" href="https://stability.ai" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Storyboard frame, plan américain shot, male detective character, over-the-shoulder framing, contre-plongée angle, rim light on shoulders, soft light fill, background slightly defocused, cinematic 16:9, desaturated color palette, pencil sketch style" title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Storyboard frame, plan américain shot, male detective character, over-the-shoulder framing, contre-plongée angle, rim light on shoulders, soft light fill, backg...</div></div><div class="vp"></div></div>
<div class="ac" data-v="openai.com"><div class="an">4</div><div class="ai" style="background:#E8F0FE"><img decoding="async" src="https://www.google.com/s2/favicons?domain=openai.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">DALL·E 3</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Accessible directement via ChatGPT. Excellente compréhension des instructions en langage naturel. Utile pour générer rapidement des thumbnails de séquences et tester des compositions.</p><div class="af"><div class="at"><span class="tg" style="background:#E8F0FE;color:#1A73E8">Prototypage rapide</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Composition</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Intégré ChatGPT</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=DALL·E+3" target="_blank">▶ Demo</a><a class="cta-a" href="https://openai.com/dall-e-3" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Storyboard thumbnail, plan d&#x27;ensemble of a forest clearing at golden hour, high key natural lighting, rule of thirds composition with protagonist in left third, symmetrical tree framing, cinematic flat 1.85:1 aspect ratio, warm color temperature, impressionist style" title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Storyboard thumbnail, plan d&#x27;ensemble of a forest clearing at golden hour, high key natural lighting, rule of thirds composition with protagonist in left third,...</div></div><div class="vp"></div></div>
<div class="ac" data-v="blackforestlabs.ai"><div class="an">5</div><div class="ai" style="background:#E8F0FE"><img decoding="async" src="https://www.google.com/s2/favicons?domain=blackforestlabs.ai&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Flux (Black Forest Labs)</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Modèle nouvelle génération aux rendus photographiques exceptionnels. Très précis sur les compositions complexes et le rendu des textures. Idéal pour des panneaux de storyboard ultra-détaillés.</p><div class="af"><div class="at"><span class="tg" style="background:#E8F0FE;color:#1A73E8">Rendu photoréaliste</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Texture & matière</span><span class="tg" style="background:#E8F0FE;color:#1A73E8">Composition précise</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Flux+(Black+Forest+Labs)" target="_blank">▶ Demo</a><a class="cta-a" href="https://blackforestlabs.ai" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Cinematic storyboard panel, bird&#x27;s eye view of a city intersection during golden hour, very long shot establishing geography, leading lines converging to center, silhouette figures, contre-jour sunlight, warm backlight, cinematic 2.35:1 scope format, photorealistic" title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Cinematic storyboard panel, bird&#x27;s eye view of a city intersection during golden hour, very long shot establishing geography, leading lines converging to center...</div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🎬</span> Génération vidéo</div>
<div class="ac" data-v="runwayml.com"><div class="an">6</div><div class="ai" style="background:#F0EAFF"><img decoding="async" src="https://www.google.com/s2/favicons?domain=runwayml.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Runway Gen-4</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Transforme une image fixe en clip vidéo avec contrôle des mouvements de caméra. Permet de créer une animatique directement depuis ses panels de storyboard en quelques clics.</p><div class="af"><div class="at"><span class="tg" style="background:#F0EAFF;color:#7C3AED">Image-to-video</span><span class="tg" style="background:#F0EAFF;color:#7C3AED">Animatique</span><span class="tg" style="background:#F0EAFF;color:#7C3AED">Mouvement caméra</span><span class="tg" style="background:#F0EAFF;color:#7C3AED">Durée plan</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Runway+Gen-4" target="_blank">▶ Demo</a><a class="cta-a" href="https://runwayml.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Camera motion: slow dolly in toward subject, subtle tilt up, soft focus pull (rack focus) from foreground to background. Lighting remains constant high key. No jump cut. Smooth tracking movement, 4 seconds duration." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Camera motion: slow dolly in toward subject, subtle tilt up, soft focus pull (rack focus) from foreground to background. Lighting remains constant high key. No ...</div></div><div class="vp"></div></div>
<div class="ac" data-v="sora.com"><div class="an">7</div><div class="ai" style="background:#F0EAFF"><img decoding="async" src="https://www.google.com/s2/favicons?domain=sora.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Sora (OpenAI)</span><span class="pl" style="background:#fce8e8;color:#c0392b;padding:2px 6px;border-radius:3px;font-size:9px">Payant</span></div><p class="ad">Génération vidéo longue durée depuis texte ou image. Excellent pour simuler des plans-séquences complexes, des mouvements fluides et des transitions entre scènes-clés d'une séquence narrative.</p><div class="af"><div class="at"><span class="tg" style="background:#F0EAFF;color:#7C3AED">Plan-séquence</span><span class="tg" style="background:#F0EAFF;color:#7C3AED">Text-to-video</span><span class="tg" style="background:#F0EAFF;color:#7C3AED">Simulation mouvement</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Sora+(OpenAI)" target="_blank">▶ Demo</a><a class="cta-a" href="https://sora.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="A continuous plan-séquence starting from a bird&#x27;s eye view of a rooftop, camera slowly arcs downward transitioning to eye level, following a woman walking, steadicam movement, dissolve to interior scene, low key dramatic lighting, cinematic 2.39:1 aspect ratio, golden hour ambiance" title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>A continuous plan-séquence starting from a bird&#x27;s eye view of a rooftop, camera slowly arcs downward transitioning to eye level, following a woman walking, stea...</div></div><div class="vp"></div></div>
<div class="ac" data-v="klingai.com"><div class="an">8</div><div class="ai" style="background:#F0EAFF"><img decoding="async" src="https://www.google.com/s2/favicons?domain=klingai.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Kling AI</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Génération vidéo de haute qualité avec un excellent contrôle du mouvement des sujets. Idéal pour simuler les mouvements de personnages dans une scène, utile pour valider un blocking avant tournage.</p><div class="af"><div class="at"><span class="tg" style="background:#F0EAFF;color:#7C3AED">Blocking acteurs</span><span class="tg" style="background:#F0EAFF;color:#7C3AED">Mouvement sujet</span><span class="tg" style="background:#F0EAFF;color:#7C3AED">Image-to-video</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Kling+AI" target="_blank">▶ Demo</a><a class="cta-a" href="https://klingai.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Two-shot scene, blocking: character A enters frame from left foreground, character B remains static in background right, camera pans slightly left to follow action, maintaining over-the-shoulder framing, eye level angle, soft fill light, natural lighting interior" title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Two-shot scene, blocking: character A enters frame from left foreground, character B remains static in background right, camera pans slightly left to follow act...</div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">📐</span> Storyboard dédié</div>
<div class="ac" data-v="wonderunit.com"><div class="an">9</div><div class="ai" style="background:#E6F7F1"><img decoding="async" src="https://www.google.com/s2/favicons?domain=wonderunit.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Storyboarder (Wonder Unit)</span><span class="pl" style="background:#e8f5ed;color:#27ae60;padding:2px 6px;border-radius:3px;font-size:9px">Gratuit</span></div><p class="ad">Logiciel gratuit dédié au storyboard avec intégration IA. Génère automatiquement des panels à partir d'un script, avec des champs pour action, dialogue, durée et notes de réalisation.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Script-to-storyboard</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Shot list auto</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Export animatique</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Storyboarder+(Wonder+Unit)" target="_blank">▶ Demo</a><a class="cta-a" href="https://wonderunit.com/storyboarder" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="SCÈNE 12 — INT. BUREAU — NUIT | Plan : Gros plan (GP) | Angle : Eye level | Mouvement : Push in lent | Durée : 3s | Action : Le personnage lit une lettre, regard descendant. Lumière : Key light latérale gauche, low key, clair-obscur marqué. | Dialogue : — | SFX : Bruissement de papier V.O." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>SCÈNE 12 — INT. BUREAU — NUIT | Plan : Gros plan (GP) | Angle : Eye level | Mouvement : Push in lent | Durée : 3s | Action : Le personnage lit une lettre, regar...</div></div><div class="vp"></div></div>
<div class="ac" data-v="boords.com"><div class="an">10</div><div class="ai" style="background:#E6F7F1"><img decoding="async" src="https://www.google.com/s2/favicons?domain=boords.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Boords</span><span class="pl" style="background:#fce8e8;color:#c0392b;padding:2px 6px;border-radius:3px;font-size:9px">Payant</span></div><p class="ad">Outil de storyboard professionnel avec génération IA intégrée. Idéal pour les agences et réalisateurs. Permet de générer une séquence de panels cohérents et de les exporter en animatique avec timing.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Panels cohérents</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Export PDF/vidéo</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Collaboration</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Animatique</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Boords" target="_blank">▶ Demo</a><a class="cta-a" href="https://boords.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Generate storyboard sequence: Scene opens with establishing shot (plan général) of empty parking garage, cut to plan moyen of protagonist entering, then close-up (gros plan) on hand gripping car keys, smash cut to exterior establishing shot. Low key lighting throughout, hard shadows, 1.85:1 flat format." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Generate storyboard sequence: Scene opens with establishing shot (plan général) of empty parking garage, cut to plan moyen of protagonist entering, then close-u...</div></div><div class="vp"></div></div>
<div class="ac" data-v="scenaristai.com"><div class="an">11</div><div class="ai" style="background:#E6F7F1"><img decoding="async" src="https://www.google.com/s2/favicons?domain=scenaristai.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Scenarist AI</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Plateforme tout-en-un : écriture du script, découpage technique et génération des panels. Transforme un traitement narratif en storyboard illustré automatiquement avec numérotation des scènes et plans.</p><div class="af"><div class="at"><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Script → Storyboard</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Découpage auto</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C">Numéro de plan</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Scenarist+AI" target="_blank">▶ Demo</a><a class="cta-a" href="https://scenaristai.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Generate a storyboard from this treatment: ACT I — The protagonist arrives at a deserted train station (establishing shot, wide). She notices a letter on a bench (insert, extreme close-up). She reads it, reaction shot (gros plan, eye level). BEAT: she looks up — empty platform (pan left, plan d&#x27;ensemble). Cut to black." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Generate a storyboard from this treatment: ACT I — The protagonist arrives at a deserted train station (establishing shot, wide). She notices a letter on a benc...</div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">✍️</span> Écriture & Structure narrative</div>
<div class="ac" data-v="claude.ai"><div class="an">12</div><div class="ai" style="background:#FFF3ED"><img decoding="async" src="https://www.google.com/s2/favicons?domain=claude.ai&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Claude (Anthropic)</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Excellent pour la structure narrative, les beat sheets et les descriptions de plans. Génère des découpages techniques précis, des dialogues et des notes de réalisation détaillées. Idéal pour construire la colonne vertébrale d'un storyboard.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF3ED;color:#CC4400">Beat sheet</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Découpage technique</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Logline</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Notes de réalisation</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Claude+(Anthropic)" target="_blank">▶ Demo</a><a class="cta-a" href="https://claude.ai" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Crée un découpage technique storyboard pour la séquence du climax (Acte III) d&#x27;un thriller urbain. Pour chaque plan indique : numéro de plan, type de plan (GP/PM/PA/PE), angle (plongée/contre-plongée/eye level), mouvement caméra (travelling/pan/dolly), transition vers le plan suivant (coupe franche/match cut/dissolve), durée estimée, et une brève description de l&#x27;action et du dialogue. Ambiance : low key, clair-obscur, 2.39:1." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Crée un découpage technique storyboard pour la séquence du climax (Acte III) d&#x27;un thriller urbain. Pour chaque plan indique : numéro de plan, type de plan (GP/P...</div></div><div class="vp"></div></div>
<div class="ac" data-v="chatgpt.com"><div class="an">13</div><div class="ai" style="background:#FFF3ED"><img decoding="async" src="https://www.google.com/s2/favicons?domain=chatgpt.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">ChatGPT (OpenAI)</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Fort en génération de synopses, loglines et arcs narratifs. Utile pour développer la structure en 3 actes, générer des beat sheets et rédiger des notes de plateau. Compatible avec DALL·E pour une chaîne texte → image.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF3ED;color:#CC4400">Synopsis</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Arc narratif</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Beat sheet</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Chaîne texte→image</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=ChatGPT+(OpenAI)" target="_blank">▶ Demo</a><a class="cta-a" href="https://chatgpt.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Rédige un beat sheet en 12 points pour un court-métrage de 15 minutes (genre : drame psychologique). Identifie : l&#x27;exposition, le turning point de l&#x27;Acte I, la montée en tension, le nœud dramatique central, le climax et la résolution. Pour chaque beat, suggère un type de plan dominant (plan général, gros plan, etc.) et une ambiance lumineuse (high key / low key)." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Rédige un beat sheet en 12 points pour un court-métrage de 15 minutes (genre : drame psychologique). Identifie : l&#x27;exposition, le turning point de l&#x27;Acte I, la ...</div></div><div class="vp"></div></div>
<div class="ac" data-v="gemini.google.com"><div class="an">14</div><div class="ai" style="background:#FFF3ED"><img decoding="async" src="https://www.google.com/s2/favicons?domain=gemini.google.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Gemini (Google)</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Capable d'analyser une image et de décrire techniquement un plan (type de plan, angle, lumière) — très utile pour reverse-engineer des références visuelles et les adapter à son storyboard. Multimodal natif.</p><div class="af"><div class="at"><span class="tg" style="background:#FFF3ED;color:#CC4400">Analyse image</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Référence visuelle</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Multimodal</span><span class="tg" style="background:#FFF3ED;color:#CC4400">Description de plan</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Gemini+(Google)" target="_blank">▶ Demo</a><a class="cta-a" href="https://gemini.google.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Analyse this reference image and describe it using storyboard technical vocabulary: identify the shot type (plan général/moyen/rapproché/gros plan), camera angle (plongée/contre-plongée/eye level/dutch angle), lighting setup (high key/low key, key light direction, fill light, rim light), aspect ratio, and suggest a camera movement (pan/tilt/dolly/steadicam) that would work for the next shot." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Analyse this reference image and describe it using storyboard technical vocabulary: identify the shot type (plan général/moyen/rapproché/gros plan), camera angl...</div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🎯</span> Cohérence visuelle</div>
<div class="ac" data-v="leonardo.ai"><div class="an">15</div><div class="ai" style="background:#FEF3C7"><img decoding="async" src="https://www.google.com/s2/favicons?domain=leonardo.ai&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Leonardo.Ai</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Spécialisé dans la cohérence de personnages entre les panels. Fonctionnalité « Character Reference » pour garder le même visage/costume sur tous les plans. Indispensable pour les storyboards avec protagonistes récurrents.</p><div class="af"><div class="at"><span class="tg" style="background:#FEF3C7;color:#D97706">Cohérence personnage</span><span class="tg" style="background:#FEF3C7;color:#D97706">Character reference</span><span class="tg" style="background:#FEF3C7;color:#D97706">Angles multiples</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Leonardo.Ai" target="_blank">▶ Demo</a><a class="cta-a" href="https://leonardo.ai" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="[Character reference attached] Same character, storyboard panel sequence: Panel 1 — plan moyen, profil gauche, eye level, natural soft light. Panel 2 — gros plan, three-quarter view, contre-plongée, hard key light from right creating clair-obscur. Panel 3 — très gros plan eyes only, eye level, rim light. Consistent art style, cinematic 16:9." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>[Character reference attached] Same character, storyboard panel sequence: Panel 1 — plan moyen, profil gauche, eye level, natural soft light. Panel 2 — gros pla...</div></div><div class="vp"></div></div>
<div class="ac" data-v="firefly.adobe.com"><div class="an">16</div><div class="ai" style="background:#FEF3C7"><img decoding="async" src="https://www.google.com/s2/favicons?domain=firefly.adobe.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Adobe Firefly</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Intégré à Photoshop et Premiere. Génère et retouche des panels directement dans le workflow Adobe. La fonction Generative Fill permet d'ajuster un cadrage, ajouter un décor ou modifier une composition après génération.</p><div class="af"><div class="at"><span class="tg" style="background:#FEF3C7;color:#D97706">Workflow Adobe</span><span class="tg" style="background:#FEF3C7;color:#D97706">Retouche panel</span><span class="tg" style="background:#FEF3C7;color:#D97706">Générative Fill</span><span class="tg" style="background:#FEF3C7;color:#D97706">Décor</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Adobe+Firefly" target="_blank">▶ Demo</a><a class="cta-a" href="https://firefly.adobe.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Extend this storyboard panel to cinémascope 2.39:1 ratio by generating background on both sides. Maintain: low key lighting, hard light source from left, clair-obscur atmosphere, industrial interior décor, night time, consistent with existing foreground elements." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Extend this storyboard panel to cinémascope 2.39:1 ratio by generating background on both sides. Maintain: low key lighting, hard light source from left, clair-...</div></div><div class="vp"></div></div>
<div class="cat"><span class="cat-icon">🎵</span> Son, V.O. & Soundtrack</div>
<div class="ac" data-v="elevenlabs.io"><div class="an">17</div><div class="ai" style="background:#FFE8F0"><img decoding="async" src="https://www.google.com/s2/favicons?domain=elevenlabs.io&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">ElevenLabs</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Génération de voix off (V.O.) ultra-réalistes à partir de texte. Permet d'ajouter des dialogues et narrations à une animatique pour tester le rythme des plans et la durée des séquences avant tournage.</p><div class="af"><div class="at"><span class="tg" style="background:#FFE8F0;color:#BE123C">Voix off (V.O.)</span><span class="tg" style="background:#FFE8F0;color:#BE123C">Dialogue</span><span class="tg" style="background:#FFE8F0;color:#BE123C">Test de rythme</span><span class="tg" style="background:#FFE8F0;color:#BE123C">Durée des plans</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=ElevenLabs" target="_blank">▶ Demo</a><a class="cta-a" href="https://elevenlabs.io" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="[V.O. Narrateur — Ton : grave, posé, 90 mots/min] « La ville ne dort jamais. Mais cette nuit-là, quelque chose avait changé. » → Durée cible : 4 secondes → correspond à un plan d&#x27;ensemble avec panoramique lent. [SFX à ajouter : bruit de circulation lointain, vent]" title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>[V.O. Narrateur — Ton : grave, posé, 90 mots/min] « La ville ne dort jamais. Mais cette nuit-là, quelque chose avait changé. » → Durée cible : 4 secondes → corr...</div></div><div class="vp"></div></div>
<div class="ac" data-v="suno.com"><div class="an">18</div><div class="ai" style="background:#FFE8F0"><img decoding="async" src="https://www.google.com/s2/favicons?domain=suno.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Suno AI</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Génération musicale à partir d'un prompt textuel. Crée une bande sonore temporaire pour accompagner l'animatique, tester l'émotion de chaque séquence et valider le rythme des transitions avant la production finale.</p><div class="af"><div class="at"><span class="tg" style="background:#FFE8F0;color:#BE123C">Bande son temp</span><span class="tg" style="background:#FFE8F0;color:#BE123C">Ambiance séquence</span><span class="tg" style="background:#FFE8F0;color:#BE123C">Rythme transition</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Suno+AI" target="_blank">▶ Demo</a><a class="cta-a" href="https://suno.com" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="Cinematic score for a thriller storyboard sequence. Act II rising tension, building from sparse low-key piano to intense orchestral swell reaching climax at 1min20. Tempo matches smash cut editing rhythm. Dark, suspenseful, Hans Zimmer style. No lyrics. Duration: 2 minutes." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>Cinematic score for a thriller storyboard sequence. Act II rising tension, building from sparse low-key piano to intense orchestral swell reaching climax at 1mi...</div></div><div class="vp"></div></div>
<div class="ac" data-v="elevenlabs.io"><div class="an">19</div><div class="ai" style="background:#FFE8F0"><img decoding="async" src="https://www.google.com/s2/favicons?domain=elevenlabs.io&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">ElevenLabs SFX</span><span class="pl" style="background:#fff8e8;color:#d4891a;padding:2px 6px;border-radius:3px;font-size:9px">Freemium</span></div><p class="ad">Génération de SFX (effets sonores) depuis un prompt. Utile pour enrichir l'animatique avec des sons d'ambiance correspondant aux décors et actions de chaque panel — bruitage, atmosphères, impacts.</p><div class="af"><div class="at"><span class="tg" style="background:#FFE8F0;color:#BE123C">SFX</span><span class="tg" style="background:#FFE8F0;color:#BE123C">Ambiance décor</span><span class="tg" style="background:#FFE8F0;color:#BE123C">Bruitage</span><span class="tg" style="background:#FFE8F0;color:#BE123C">Animatique sonore</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=ElevenLabs+SFX" target="_blank">▶ Demo</a><a class="cta-a" href="https://elevenlabs.io/sound-effects" target="_blank">Accéder →</a></div></div><div style="background:#1e1a15;border-radius:8px;padding:8px 12px;margin-top:8px;font-size:10px;color:#e8dcc8;line-height:1.5;font-family:monospace;cursor:pointer" onclick="event.stopPropagation();navigator.clipboard.writeText(this.dataset.p);this.style.outline='2px solid #27ae60';setTimeout(()=>this.style.outline='',1000)" data-p="SFX for storyboard panel: establishing shot of rainy city alley, night scene. Sound: distant traffic, rain on pavement, dripping water from rooftop, occasional distant siren. Duration: 6 seconds, seamlessly loopable, low key urban ambiance." title="Copier"><span style="font-size:8px;color:#888;display:block;margin-bottom:3px">PROMPT · clic = copier</span>SFX for storyboard panel: establishing shot of rainy city alley, night scene. Sound: distant traffic, rain on pavement, dripping water from rooftop, occasional ...</div></div><div class="vp"></div></div>
<div class="ac" data-v="github.com"><div class="an">20</div><div class="ai" style="background:#FEF3C7"><img decoding="async" src="https://www.google.com/s2/favicons?domain=github.com&sz=64" alt="" onerror="this.style.display='none'"></div><div class="ab"><div class="ah"><span class="nm">Fooocus</span><span class="pl" style="background:#e8f5ed;color:#27ae60;padding:2px 6px;border-radius:3px;font-size:9px">Gratuit</span></div><p class="ad">Interface simplifiée pour Stable Diffusion / Flux. Génération d'images de haute qualité sans configuration complexe. ControlNet et IP-Adapter intégrés pour la cohérence visuelle entre panels.</p><div class="af"><div class="at"><span class="tg" style="background:#FEF3C7;color:#D97706">Workflow simplifié</span><span class="tg" style="background:#FEF3C7;color:#D97706">Cohérence totale</span><span class="tg" style="background:#FEF3C7;color:#D97706">ControlNet</span></div><div class="ctas"><a class="cta-d" href="https://www.youtube.com/results?search_query=Fooocus+tutorial" target="_blank">▶ Demo</a><a class="cta-a" href="https://github.com/lllyasviel/Fooocus" target="_blank">Accéder →</a></div></div></div><div class="vp"></div></div>


</div>
<div class="sb-panel" id="sb-glossaire">
<div class="cat"><span class="cat-icon">📖</span> Structure du récit</div>
<div class="ac"><div class="an">01</div><div class="ai" style="background:#FFF3ED"><span style="font-size:20px">📖</span></div><div class="ab"><div class="ah"><span class="nm">Structure du récit</span><span class="pl">17 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Acte I');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Acte I</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Acte II');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Acte II</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Acte III');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Acte III</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Arc narratif');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Arc narratif</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Beat');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Beat</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Beat sheet');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Beat sheet</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Climax');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Climax</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Dénouement');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Dénouement</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Exposition');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Exposition</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Intrigue');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Intrigue</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Logline');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Logline</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Montée en tension');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Montée en tension</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Nœud dramatique');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Nœud dramatique</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Point de bascule');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Point de bascule</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Prologue');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Prologue</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Résolution');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Résolution</span><span class="tg" style="background:#FFF3ED;color:#CC4400;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Scène-clé');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Scène-clé</span></div></div></div></div>
<div class="cat"><span class="cat-icon">🎥</span> Cadrage & Plans</div>
<div class="ac"><div class="an">02</div><div class="ai" style="background:#E8F0FE"><span style="font-size:20px">🎥</span></div><div class="ab"><div class="ah"><span class="nm">Cadrage & Plans</span><span class="pl">14 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Amorce');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Amorce</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Cadre');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Cadre</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Champ');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Champ</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Contre-champ');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Contre-champ</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Establishing shot');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Establishing shot</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Gros plan (GP)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Gros plan (GP)</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Hors-champ');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Hors-champ</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Insert');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Insert</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Over-the-shoulder (OTS)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Over-the-shoulder (OTS)</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Plan américain (PA)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Plan américain (PA)</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Plan densemble (PE)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Plan d'ensemble (PE)</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Plan général (PG)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Plan général (PG)</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Plan moyen (PM)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Plan moyen (PM)</span><span class="tg" style="background:#E8F0FE;color:#1A73E8;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Plan poitrine (PP)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Plan poitrine (PP)</span></div></div></div></div>
<div class="cat"><span class="cat-icon">📐</span> Angles & Axes de caméra</div>
<div class="ac"><div class="an">03</div><div class="ai" style="background:#F0EAFF"><span style="font-size:20px">📐</span></div><div class="ab"><div class="ah"><span class="nm">Angles & Axes de caméra</span><span class="pl">9 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Angle dattaque');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Angle d'attaque</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Birds eye view');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Bird's eye view</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Caméra subjective');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Caméra subjective</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Contre-plongée');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Contre-plongée</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Dutch angle');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Dutch angle</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Eye level');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Eye level</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Plongée');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Plongée</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Profil');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Profil</span><span class="tg" style="background:#F0EAFF;color:#7C3AED;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Top shot');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Top shot</span></div></div></div></div>
<div class="cat"><span class="cat-icon">🎬</span> Mouvements de caméra</div>
<div class="ac"><div class="an">04</div><div class="ai" style="background:#E6F7F1"><span style="font-size:20px">🎬</span></div><div class="ab"><div class="ah"><span class="nm">Mouvements de caméra</span><span class="pl">12 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Arc');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Arc</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Caméra portée');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Caméra portée</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Dolly in');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Dolly in</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Dolly out');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Dolly out</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Filé (swish pan)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Filé (swish pan)</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Panoramique (pan)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Panoramique (pan)</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Plan-séquence');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Plan-séquence</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Push in');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Push in</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Rack focus');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Rack focus</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Steadicam');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Steadicam</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Tilt down');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Tilt down</span><span class="tg" style="background:#E6F7F1;color:#0D8C6C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Tilt up');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Tilt up</span></div></div></div></div>
<div class="cat"><span class="cat-icon">✂️</span> Transitions</div>
<div class="ac"><div class="an">05</div><div class="ai" style="background:#FEF3C7"><span style="font-size:20px">✂️</span></div><div class="ab"><div class="ah"><span class="nm">Transitions</span><span class="pl">9 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Coupe franche');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Coupe franche</span><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Cut to black');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Cut to black</span><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Dissolve (fondu enchaîné)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Dissolve (fondu enchaîné)</span><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Ellipse');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Ellipse</span><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Fade in');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Fade in</span><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Fade out');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Fade out</span><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Flash cut');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Flash cut</span><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Jump cut');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Jump cut</span><span class="tg" style="background:#FEF3C7;color:#D97706;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Match cut');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Match cut</span></div></div></div></div>
<div class="cat"><span class="cat-icon">🎭</span> Composition & Mise en scène</div>
<div class="ac"><div class="an">06</div><div class="ai" style="background:#FFE8F0"><span style="font-size:20px">🎭</span></div><div class="ab"><div class="ah"><span class="nm">Composition & Mise en scène</span><span class="pl">9 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Action line (axe des 180°)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Action line (axe des 180°)</span><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Background (arrière-plan)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Background (arrière-plan)</span><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Blocking (placement des acteurs)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Blocking (placement des acteurs)</span><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Foreground (premier plan)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Foreground (premier plan)</span><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Golden ratio');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Golden ratio</span><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Lead room');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Lead room</span><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Lignes de force');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Lignes de force</span><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Look room (nose room)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Look room (nose room)</span><span class="tg" style="background:#FFE8F0;color:#BE123C;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Profondeur de champ');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Profondeur de champ</span></div></div></div></div>
<div class="cat"><span class="cat-icon">💡</span> Lumière & Ambiance</div>
<div class="ac"><div class="an">07</div><div class="ai" style="background:#E5F9FA"><span style="font-size:20px">💡</span></div><div class="ab"><div class="ah"><span class="nm">Lumière & Ambiance</span><span class="pl">9 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Contre-jour');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Contre-jour</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Clair-obscur');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Clair-obscur</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Fill light');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Fill light</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Hard light');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Hard light</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('High key');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">High key</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Key light');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Key light</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Low key');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Low key</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Lumière naturelle');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Lumière naturelle</span><span class="tg" style="background:#E5F9FA;color:#00A5AB;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Rim light');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Rim light</span></div></div></div></div>
<div class="cat"><span class="cat-icon">📝</span> Annotations & Format</div>
<div class="ac"><div class="an">08</div><div class="ai" style="background:#E6F2FF"><span style="font-size:20px">📝</span></div><div class="ab"><div class="ah"><span class="nm">Annotations & Format</span><span class="pl">12 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Action');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Action</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Animatique');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Animatique</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Case (panel)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Case (panel)</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Décor');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Décor</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Description de plan');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Description de plan</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Dialogue');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Dialogue</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Durée');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Durée</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Flèche de mouvement');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Flèche de mouvement</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Miniature (thumbnail)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Miniature (thumbnail)</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Note de réalisation');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Note de réalisation</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Numéro de plan');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Numéro de plan</span><span class="tg" style="background:#E6F2FF;color:#005EA6;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Numéro de scène');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Numéro de scène</span></div></div></div></div>
<div class="cat"><span class="cat-icon">📏</span> Formats & Ratio</div>
<div class="ac"><div class="an">09</div><div class="ai" style="background:#F5F0FF"><span style="font-size:20px">📏</span></div><div class="ab"><div class="ah"><span class="nm">Formats & Ratio</span><span class="pl">9 termes</span></div><p class="ad">Cliquez sur un terme pour le copier dans vos prompts IA.</p><div class="af"><div class="at" style="flex-wrap:wrap"><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('1.33:1 (4:3)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">1.33:1 (4:3)</span><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('1.78:1 (16:9)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">1.78:1 (16:9)</span><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('1.85:1 (Flat)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">1.85:1 (Flat)</span><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('2.35:1 (Scope)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">2.35:1 (Scope)</span><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('2.39:1 (Cinémascope)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">2.39:1 (Cinémascope)</span><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Format carré (1:1)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Format carré (1:1)</span><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Format vertical (9:16)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Format vertical (9:16)</span><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Letterbox');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Letterbox</span><span class="tg" style="background:#F5F0FF;color:#6D28D9;cursor:pointer;margin:2px" onclick="event.stopPropagation();navigator.clipboard.writeText('Masque (matte)');this.style.outline='2px solid #10B981';setTimeout(()=>this.style.outline='',800)">Masque (matte)</span></div></div></div></div>

</div>
</section>
<div class="print-contact" id="pcd-print-contact">
<img decoding="async" src="https://presentcomposedesign.fr/wp-content/uploads/2026/03/abstract-gradient-background-Formation-page@1-2048x1111abstract-gradient-background-Formation_PresentComposedesign_footer.png" class="pc-bg" alt="">
<div class="pc-inner">
<a href="https://presentcomposedesign.fr" target="_blank" class="pc-logo"><img decoding="async" src="https://presentcomposedesign.fr/wp-content/uploads/2025/07/Present-Compose-design_logo-image.svg" alt="PCD"></a>
<div class="pc-info">
<div class="pc-name">Alban Desbarax · Présent Composé Design</div>
<div class="pc-role">Designer 360° · Directeur Artistique · Enseignant · Toulouse</div>
<div class="pc-phrase">Ma sélection d'outils et applications préconisés pour les formations universitaires et professionnelles dans les secteurs créatifs</div>
<div class="pc-links">
<a href="https://fr.linkedin.com/in/alban-desbarax-present-compose-design" target="_blank" class="pc-li" title="LinkedIn">in</a>
<a href="#" onclick="window.location=String.fromCharCode(109,97,105,108,116,111,58)+String.fromCharCode(99,111,110,116,97,99,116,64)+String.fromCharCode(112,114,101,115,101,110,116,99,111,109,112,111,115,101,100,101,115,105,103,110,46,102,114);return false" class="pc-email">&#9993; <span class="eml"></span></a>
<a href="tel:+33683949667">&#9742; +33 6 83 94 96 67</a>
<a href="https://buymeacoffee.com/presentcomposedesign" class="pc-thx" target="_blank">&#9829; Remercier / Soutenir</a>
<a href="https://presentcomposedesign.fr/contact/" class="pc-cta" target="_blank">&#8599; Mettre en place une formation</a>
</div>
</div>
</div>
</div>
<div class="print-footer"><div class="pf-b"><a href="https://presentcomposedesign.fr" target="_blank">Présent Composé Design</a> / Alban Desbarax</div><div class="pf-i">12, bis rue Louis Plana 31500 Toulouse · +33 (0) 683 949 667 · <span class="eml"></span> · SIREN : 789 583 242 000 35</div></div>
<div class="AP" id="pcd-ap"><div class="AC"><h3>📋 Participants <span class="cb" id="pcd-cb">0</span></h3><p class="as">Visible uniquement sur votre navigateur</p><div id="pcd-pl"></div><div id="pcd-ab" style="display:none"><button class="bx bx-b" onclick="pExp()">📥 CSV</button><button class="bx bx-g" onclick="pPrint()">🖨 PDF</button><button class="bx bx-r" onclick="pClr()">🗑 Reset</button></div></div></div>
</div>

<script>

var P=[];try{P=JSON.parse(localStorage.getItem('pcd_participants')||'[]')}catch(e){}


/* ── Demo button: opens YouTube (full page with sound) ── */
function pDm(k){
  var v=C.VIDEOS[k]; if(!v) return false;
  if(v.id) window.open('https://www.youtube.com/watch?v='+v.id,'_blank');
  else window.open('https://www.youtube.com/results?search_query='+encodeURIComponent(v.q),'_blank');
  return false;
}

/* ── Form ── */
function pGenCode(fn,ln){
  fn=(fn||'').toLowerCase().replace(/[^a-z]/g,'');
  ln=(ln||'').toLowerCase().replace(/[^a-z]/g,'');
  var a=fn.charAt(0),b=fn.charAt(1),c=ln.charAt(0),d=ln.charAt(1);
  var s='';
  if(a)s+=(a.charCodeAt(0)-96);
  if(b)s+=(b.charCodeAt(0)-96);
  if(c)s+=(c.charCodeAt(0)-96);
  if(d)s+=(d.charCodeAt(0)-96);
  return s.substring(0,4);
}
function pSub(){
  var fn=document.getElementById('pcd-fn').value.trim();
  var ln=document.getElementById('pcd-ln').value.trim();
  var em=document.getElementById('pcd-em').value.trim();
  var ph=document.getElementById('pcd-ph').value.trim();
  var pr=document.getElementById('pcd-pr').value;
  var sc=document.getElementById('pcd-sc').value.trim();
  var code=document.getElementById('pcd-code').value.trim().toUpperCase();
  if(!fn||!ln||!em||!code){
    var b=document.getElementById('pcd-sub');b.style.animation='pSH .4s';
    setTimeout(function(){b.style.animation=''},500);
    alert('Merci de remplir tous les champs obligatoires (prénom, nom, email et code).');return;
  }
  if(!em.includes('@')||!em.includes('.')){alert('Email invalide.');return;}
  /* Master key check (obfuscated) */
  var mk=String.fromCharCode(50,75,49,54);var mk2=String.fromCharCode(70,79,82,77);var mk3=String.fromCharCode(50,48,50,54);
  var expected=pGenCode(fn,ln);
  if(code!==expected&&code!==mk&&code!==mk2&&code!==mk3){
    alert('Code d\'acc\u00e8s incorrect. Votre code personnel est bas\u00e9 sur votre pr\u00e9nom et nom. Demandez-le \u00e0 votre formateur si besoin.');return;
  }
  var isAdmin=(code===mk||code===mk2||code===mk3);
  P.push({firstName:fn,lastName:ln,email:em,phone:ph,profile:pr,sector:pr==='pro_autre'?sc:'',date:new Date().toLocaleString('fr-FR'),guide:currentGuide});
  try{localStorage.setItem('pcd_participants',JSON.stringify(P))}catch(e){}
  document.getElementById('pcd-fo').classList.remove('on');
  document.getElementById('pcd-land').style.display='none';
  if(currentGuide==='ia'){document.getElementById('pcd-guide').classList.add('on')}
  else if(currentGuide==='sb'){document.getElementById('pcd-guide-sb').style.display='block'}
  else{document.getElementById('pcd-guide-os').style.display='block'}
  var t=document.getElementById('pcd-toast');t.classList.add('on');
  setTimeout(function(){t.classList.remove('on')},3500);
  pUA();
  setTimeout(function(){var ap=document.getElementById('pcd-ap');if(ap&&ap.classList.contains('on'))ap.scrollIntoView({behavior:'smooth',block:'end'})},500);
}

/* ── Admin ── */
function pUA(){if(!P.length){document.getElementById('pcd-ap').classList.remove('on');return}document.getElementById('pcd-ap').classList.add('on');document.getElementById('pcd-ab').style.display='block';document.getElementById('pcd-cb').textContent=P.length;var L={'etudiant':'Étudiant·e','pro_design':'Pro design','pro_autre':'Pro autre','entrepreneur':'Entrepreneur','curieux':'Curieux·se','':'—'};var h='<table class="tb"><thead><tr><th>Prénom</th><th>Nom</th><th>Email</th><th>Tél.</th><th>Profil</th><th>Secteur</th><th>Date</th></tr></thead><tbody>';P.forEach(function(p){h+='<tr><td>'+pE(p.firstName)+'</td><td>'+pE(p.lastName)+'</td><td>'+pE(p.email)+'</td><td>'+pE(p.phone||'—')+'</td><td>'+(L[p.profile]||'—')+'</td><td>'+pE(p.sector||'—')+'</td><td>'+pE(p.date)+'</td></tr>'});h+='</tbody></table>';document.getElementById('pcd-pl').innerHTML=h}
function pE(t){var d=document.createElement('div');d.textContent=t;return d.innerHTML}
function pExp(){if(!P.length)return;var c='Prénom,Nom,Email,Téléphone,Profil,Secteur,Date\n';P.forEach(function(p){c+='"'+p.firstName+'","'+p.lastName+'","'+p.email+'","'+(p.phone||'')+'","'+(p.profile||'')+'","'+(p.sector||'')+'","'+p.date+'"\n'});var b=new Blob(['\uFEFF'+c],{type:'text/csv;charset=utf-8;'}),a=document.createElement('a');a.href=URL.createObjectURL(b);a.download='participants_formation_ia_pcd.csv';a.click()}
function pPrint(){window.print()}
function pClr(){if(!confirm('Supprimer tous les participants ?'))return;P=[];try{localStorage.removeItem('pcd_participants')}catch(e){}pUA()}
if(P.length>0)pUA();

/* Fix Demo buttons: set real hrefs for PDF print */
document.querySelectorAll('#pcd-guide .cta-d').forEach(function(btn){
  var card=btn.closest('.ac[data-v]');
  if(!card)return;
  var key=card.getAttribute('data-v');
  var v=C.VIDEOS[key];
  if(!v)return;
  if(v.id){btn.href='https://www.youtube.com/watch?v='+v.id}
  else{btn.href='https://www.youtube.com/results?search_query='+encodeURIComponent(v.q)}
  btn.setAttribute('target','_blank');
});
/* OS guide Demo buttons already have real hrefs */

/* Video hover: autoplay for all cards */
document.querySelectorAll('.ac[data-v]').forEach(function(card){
  var key=card.getAttribute('data-v'),vp=card.querySelector('.vp');
  if(!vp)return;
  var v=C.VIDEOS?C.VIDEOS[key]:null;
  var demoBtn=card.querySelector('.cta-d');
  var demoHref=demoBtn?demoBtn.getAttribute('href'):'';
  var vid='';
  if(v&&v.id){vid=v.id}
  else if(demoHref){var m=demoHref.match(/watch\?v=([^&]+)/);if(m)vid=m[1]}
  var searchQ=(v&&v.q)?v.q:'';
  if(!searchQ&&demoHref){var sq=demoHref.match(/search_query=([^&]+)/);if(sq)searchQ=decodeURIComponent(sq[1]).replace(/\+/g,' ')}
  if(!vid)return;
  var timer=null;
  card.addEventListener('mouseenter',function(){
    timer=setTimeout(function(){
      var src='https://www.youtube.com/embed/'+vid+'?autoplay=1&mute=1&rel=0&modestbranding=1&controls=0';
      vp.innerHTML='<iframe src="'+src+'" allow="autoplay;encrypted-media" allowfullscreen loading="lazy"></iframe>';
      vp.classList.add('open');
    },300);
  });
  card.addEventListener('mouseleave',function(){
    clearTimeout(timer);
    vp.classList.remove('open');
    setTimeout(function(){vp.innerHTML=''},400);
  });
});
document.querySelectorAll('.eml').forEach(function(el){el.textContent=String.fromCharCode(99,111,110,116,97,99,116,64,112,114,101,115,101,110,116,99,111,109,112,111,115,101,100,101,115,105,103,110,46,102,114)});

/* Hide repeating footer when contact banner is visible (last page) */
window.addEventListener('beforeprint',function(){
  var pf=document.querySelector('.print-footer');
  var pc=document.querySelector('.print-contact');
  if(pf&&pc){pf.style.display='none'}
});
window.addEventListener('afterprint',function(){
  var pf=document.querySelector('.print-footer');
  if(pf){pf.style.display=''}
});
</script>
</body>
</html>				</div>
				</div>
				</div>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/formations/">Formations</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Canyon-sound</title>
		<link>https://presentcomposedesign.fr/canyon-sound/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 19 Jan 2026 09:44:07 +0000</pubDate>
				<category><![CDATA[Design produit]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=35701</guid>

					<description><![CDATA[<p>Canyon Ambix Sound Expérience sonore Ambix</p>
<p>Cet article <a href="https://presentcomposedesign.fr/canyon-sound/">Canyon-sound</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="35701" class="elementor elementor-35701">
				<div class="elementor-element elementor-element-cbfcc19 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="cbfcc19" data-element_type="container" data-e-type="container">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-80547c5 elementor-widget elementor-widget-html" data-id="80547c5" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!DOCTYPE html>
<html>
<head>
    <title>Canyon Ambix Sound</title>
    <script>
        // Initialiser l'AudioContext et démarrer la lecture
        window.addEventListener('load', () => {
            const audioContext = new (window.AudioContext || window.webkitAudioContext)();
            const audioElement = new Audio('https://presentcomposedesign.fr/wp-content/uploads/2026/01/CANYON-AMBIX.wav');

            // Configurer les paramètres audio
            audioElement.loop = true;
            audioElement.volume = 0.6;

            // Créer les nœuds audio pour le contrôle du volume
            const sourceNode = audioContext.createMediaElementSource(audioElement);
            const gainNode = audioContext.createGain();
            gainNode.gain.value = 0.6;

            // Connecter les nœuds
            sourceNode.connect(gainNode);
            gainNode.connect(audioContext.destination);

            // Fonction pour démarrer la lecture
            const startPlayback = () => {
                audioElement.play().catch(error => {
                    console.log("Erreur de lecture :", error);
                });
            };

            // Tentative de démarrage automatique
            startPlayback();

            // Écouter les interactions utilisateur pour reprendre la lecture si nécessaire
            document.body.addEventListener('click', () => {
                if (audioContext.state === 'suspended') {
                    audioContext.resume().then(() => {
                        startPlayback();
                    });
                }
            });
        });
    </script>
</head>
<body>
    <p style="text-align: center; margin-top: 50px;">Expérience sonore Ambix</p>
</body>
</html>
				</div>
				</div>
					</div>
				</div>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/canyon-sound/">Canyon-sound</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Curiosity</title>
		<link>https://presentcomposedesign.fr/curiosity/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 25 Dec 2025 18:47:39 +0000</pubDate>
				<category><![CDATA[[ia]]]></category>
		<category><![CDATA[Design graphique]]></category>
		<category><![CDATA[Design produit]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=35140</guid>

					<description><![CDATA[<p>Curiosity Viewer ● Curiosity Chat 🧠 Curiosity 🗑️ ⚙️ 👋 Bonjour, Je suis Curiosity, votre oracle culturel français. Posez-moi n&#8217;importe quelle question ! 🎤 ▶️ ⚙️ Réglages Avancés ✕ 🎨 Apparence Thème Choisissez le thème d&#8217;affichage Auto ☀️ Clair 🌙 Sombre Affichage du personnage Montrer/cacher Curiosity Afficher le personnage Curiosity Taille de la fenêtre Ajuster la taille selon vos préférences 100% 🎤 Synthèse Vocale Voix française Sélectionnez la voix de lecture Vitesse de lecture 1.0x Lecture automatique des réponses Lire les sources à voix haute 💬 Conversation Mode de réponse Longueur des réponses de Curiosity Concis (2 phrases)Détaillé (5 phrases)Complet (10+ phrases) Historique conservé Nombre d&#8217;échanges mémorisés 10 Sauvegarder l&#8217;historique (localStorage) 🔧 Avancé URL de l&#8217;API Ne modifiez que si nécessaire Délai d&#8217;affichage des yeux Durée d&#8217;affichage des recherches (secondes) 8s Effet parallax sur le personnage Mode debug (console) 💾 Sauvegarder les paramètres</p>
<p>Cet article <a href="https://presentcomposedesign.fr/curiosity/">Curiosity</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="35140" class="elementor elementor-35140">
				<div class="elementor-element elementor-element-11b78ac e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="11b78ac" data-element_type="container" data-e-type="container">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-cfacc9d elementor-widget elementor-widget-html" data-id="cfacc9d" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Curiosity Viewer</title>
    <style>
        :root {
            --phi: 1.618;
            --viewer-size: min(500px, 80vmin);
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            background: #f5f7fa;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
        }

        .curiosity-viewer {
            position: relative;
            width: var(--viewer-size);
            height: var(--viewer-size);
            transition: transform 0.1s ease-out;
        }

        /* Base character image */
        .character-base {
            width: 100%;
            height: 100%;
            position: absolute;
            top: 0;
            left: 0;
        }

        .character-base img {
            width: 100%;
            height: 100%;
            object-fit: contain;
            filter: drop-shadow(0 20px 40px rgba(0,0,0,0.15));
        }

        /* Screen container with perfect SVG mask */
        .screen-container {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            -webkit-mask-image: url('https://presentcomposedesign.fr/wp-content/uploads/2025/12/Curiosity_mask-screen-transparent_PresentComposedesign.svg');
            mask-image: url('https://presentcomposedesign.fr/wp-content/uploads/2025/12/Curiosity_mask-screen-transparent_PresentComposedesign.svg');
            -webkit-mask-size: 100% 100%;
            mask-size: 100% 100%;
            -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
            -webkit-mask-position: center;
            mask-position: center;
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 0;
            padding: 0;
            background: #000;
        }

        /* Left Eye - Code */
        .left-eye {
            width: 100%;
            height: 100%;
            background: #000;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            padding: 8%;
            font-family: 'Courier New', monospace;
            font-size: 7px;
            line-height: 1.5;
            color: #fff;
            opacity: 0;
            transition: opacity 0.3s;
        }

        .left-eye.active {
            opacity: 1;
            animation: scrollCode 6s linear infinite;
        }

        @keyframes scrollCode {
            0% { transform: translateY(0); }
            100% { transform: translateY(-30%); }
        }

        .code-line {
            white-space: nowrap;
            text-shadow: 0 0 8px #fff;
            margin-bottom: 1px;
        }

        /* Right Eye - Preview */
        .right-eye {
            width: 100%;
            height: 100%;
            background: #fff;
            overflow: hidden;
            position: relative;
        }

        .eye-preview {
            width: 100%;
            height: 100%;
            display: none;
        }

        .eye-preview.active {
            display: block;
        }

        .eye-preview iframe {
            width: 400%;
            height: 400%;
            border: none;
            transform: scale(0.25);
            transform-origin: top left;
            pointer-events: none;
        }

        .preview-placeholder {
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #fff;
            font-family: monospace;
            font-size: 8px;
            text-align: center;
            background: #000;
        }

        /* Status Indicator */
        .status-indicator {
            position: absolute;
            bottom: 8%;
            right: 12%;
            width: calc(var(--viewer-size) * 0.08);
            height: calc(var(--viewer-size) * 0.08);
            border-radius: 50%;
            background: #4ade80;
            box-shadow: 0 0 0 calc(var(--viewer-size) * 0.02) rgba(74,222,128,0.3);
            z-index: 100;
            transition: all 0.3s ease;
        }

        .status-indicator.thinking {
            background: #fbbf24;
            box-shadow: 0 0 0 calc(var(--viewer-size) * 0.02) rgba(251,191,36,0.3);
            animation: pulse 1.5s infinite;
        }

        .status-indicator.error {
            background: #f87171;
            box-shadow: 0 0 0 calc(var(--viewer-size) * 0.02) rgba(248,113,113,0.3);
        }

        @keyframes pulse {
            0%, 100% { transform: scale(1); }
            50% { transform: scale(1.2); }
        }

        /* Responsive */
        @media (max-width: 768px) {
            :root {
                --viewer-size: min(320px, 85vmin);
            }
            .left-eye {
                font-size: 6px;
            }
        }
    </style>
</head>
<body>
    <div class="curiosity-viewer" id="viewer">
        <!-- Character Base -->
        <div class="character-base">
            <img decoding="async" id="characterImg" 
                 src="https://presentcomposedesign.fr/wp-content/uploads/2025/12/Curiosity_OFF_PresentComposedesign.png"
                 alt="Curiosity">
        </div>

        <!-- Eyes Screen -->
        <div class="screen-container">
            <!-- Left Eye -->
            <div class="left-eye" id="leftEye"></div>
            
            <!-- Right Eye -->
            <div class="right-eye">
                <div id="rightEye" class="eye-preview">
                    <div class="preview-placeholder">●</div>
                </div>
            </div>
        </div>

        <!-- Status -->
        <div id="statusIndicator" class="status-indicator"></div>
    </div>

    <script>
        const STATES = {
            OFF: 'https://presentcomposedesign.fr/wp-content/uploads/2025/12/Curiosity_OFF_PresentComposedesign.png',
            ON: 'https://presentcomposedesign.fr/wp-content/uploads/2025/12/Curiosity_ON_PresentComposedesign.png',
            THINKING: 'https://presentcomposedesign.fr/wp-content/uploads/2025/12/Curiosity_requesting-sample_PresentComposedesign.png',
            GOOD: 'https://presentcomposedesign.fr/wp-content/uploads/2025/12/Curiosity_good_PresentComposedesign.png',
            BAD: 'https://presentcomposedesign.fr/wp-content/uploads/2025/12/Curiosity_bad_PresentComposedesign.png'
        };

        // API pour contrôler le viewer depuis l'extérieur
        window.CuriosityViewer = {
            setState(state) {
                document.getElementById('characterImg').src = STATES[state] || STATES.ON;
            },

            setStatus(status) {
                const indicator = document.getElementById('statusIndicator');
                indicator.className = 'status-indicator ' + (status || '');
            },

            showCode(query) {
                const leftEye = document.getElementById('leftEye');
                const code = [
                    `> web_search("${query}")`,
                    `> Connecting...`,
                    `> fetch wikipedia.org`,
                    `> fetch meteofrance.com`,
                    `> fetch coingecko.com`,
                    `> Parsing HTML...`,
                    `> const data = await parse()`,
                    `> Extracting content...`,
                    `> Processing 12 sources`,
                    `> Analyzing data...`,
                    `> Building response...`,
                    `> ✓ Complete`,
                    ``,
                    `// ${new Date().toLocaleTimeString()}`,
                    `// Query: "${query}"`,
                    `// Confidence: 96%`
                ];
                
                leftEye.innerHTML = code.map(line => 
                    `<div class="code-line">${line}</div>`
                ).join('');
                
                leftEye.classList.add('active');
            },

            showPreview(url) {
                const rightEye = document.getElementById('rightEye');
                if (url && url.startsWith('http')) {
                    rightEye.innerHTML = `<iframe src="${url}" sandbox="allow-same-origin"></iframe>`;
                    rightEye.classList.add('active');
                }
            },

            clearEyes() {
                const leftEye = document.getElementById('leftEye');
                const rightEye = document.getElementById('rightEye');
                
                leftEye.classList.remove('active');
                rightEye.classList.remove('active');
                
                setTimeout(() => {
                    leftEye.innerHTML = '';
                    rightEye.innerHTML = '<div class="preview-placeholder">●</div>';
                }, 300);
            }
        };

        // Parallax
        document.addEventListener('mousemove', e => {
            const x = (e.clientX / window.innerWidth - 0.5) * 12;
            const y = (e.clientY / window.innerHeight - 0.5) * 12;
            document.getElementById('viewer').style.transform = `translate(${x}px, ${y}px)`;
        });

        // Init
        window.CuriosityViewer.setState('OFF');
        setTimeout(() => {
            window.CuriosityViewer.setState('ON');
        }, 1000);

        // Écouter les messages du chat
        window.addEventListener('message', (event) => {
            const { action, data } = event.data;
            
            switch(action) {
                case 'setState':
                    window.CuriosityViewer.setState(data);
                    break;
                case 'setStatus':
                    window.CuriosityViewer.setStatus(data);
                    break;
                case 'showCode':
                    window.CuriosityViewer.showCode(data);
                    break;
                case 'showPreview':
                    window.CuriosityViewer.showPreview(data);
                    break;
                case 'clearEyes':
                    window.CuriosityViewer.clearEyes();
                    break;
            }
        });
    </script>
</body>
</html>				</div>
				</div>
				<div class="elementor-element elementor-element-d5da671 elementor-widget elementor-widget-html" data-id="d5da671" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Curiosity Chat</title>
    <style>
        /* ===================================
           CURIOSITY CHAT v3.2 - Golden Ratio
           © Présent Composé Design
           =================================== */
        
        :root {
            --phi: 1.618;
            --unit: 20px;
            
            /* Espacements selon le nombre d'or */
            --space-xxs: calc(var(--unit) / var(--phi) / var(--phi) / var(--phi));
            --space-xs: calc(var(--unit) / var(--phi) / var(--phi));
            --space-s: calc(var(--unit) / var(--phi));
            --space-m: var(--unit);
            --space-l: calc(var(--unit) * var(--phi));
            --space-xl: calc(var(--unit) * var(--phi) * var(--phi));
            --space-xxl: calc(var(--unit) * var(--phi) * var(--phi) * var(--phi));
            
            /* Tailles selon le nombre d'or */
            --text-xs: calc(var(--unit) / var(--phi) / var(--phi));
            --text-s: calc(var(--unit) / var(--phi));
            --text-m: var(--unit);
            --text-l: calc(var(--unit) * var(--phi));
            --text-xl: calc(var(--unit) * var(--phi) * var(--phi));
            
            --border-radius-s: calc(var(--unit) / var(--phi));
            --border-radius-m: var(--unit);
            --border-radius-l: calc(var(--unit) * var(--phi));
            
            --bg-light: #F5F7FA;
            --bg-dark: #0a0e27;
            --card-light: rgba(255,255,255,0.98);
            --card-dark: rgba(15,20,40,0.98);
            --text-light: #1a1a2e;
            --text-dark: #e8e9f3;
            --accent: #667eea;
            --accent-secondary: #764ba2;
            --success: #4ade80;
            --warning: #fbbf24;
            --error: #f87171;
            
            --chat-width: calc(600px);
            --chat-max-width: calc(var(--chat-width) * var(--phi));
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', sans-serif;
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
            line-height: var(--phi);
            transition: background-color 0.3s ease;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: var(--space-m);
        }

        body.light-mode {
            background: var(--bg-light);
            color: var(--text-light);
        }

        body.dark-mode {
            background: var(--bg-dark);
            color: var(--text-dark);
        }

        /* Main Chat Container */
        .chat-container {
            width: 100%;
            max-width: var(--chat-max-width);
        }

        .chat-interface {
            width: 100%;
            backdrop-filter: blur(calc(var(--space-m) * var(--phi)));
            -webkit-backdrop-filter: blur(calc(var(--space-m) * var(--phi)));
            border-radius: var(--border-radius-l);
            padding: var(--space-l);
            box-shadow: 0 var(--space-m) var(--space-xl) rgba(0,0,0,0.15);
            transition: all 0.3s ease;
        }

        .light-mode .chat-interface {
            background: var(--card-light);
            border: 1px solid rgba(0,0,0,0.06);
        }

        .dark-mode .chat-interface {
            background: var(--card-dark);
            border: 1px solid rgba(255,255,255,0.1);
        }

        /* Header */
        .chat-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: var(--space-l);
            padding-bottom: var(--space-s);
            border-bottom: 1px solid rgba(102,126,234,0.1);
        }

        .chat-title {
            font-size: var(--text-xl);
            font-weight: 800;
            background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            letter-spacing: -0.02em;
        }

        .header-actions {
            display: flex;
            gap: var(--space-xs);
        }

        .icon-btn {
            width: calc(var(--space-l) * var(--phi));
            height: calc(var(--space-l) * var(--phi));
            border-radius: 50%;
            border: none;
            background: rgba(102,126,234,0.1);
            color: var(--accent);
            cursor: pointer;
            display: grid;
            place-items: center;
            transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
            font-size: var(--text-m);
        }

        .icon-btn.danger {
            background: rgba(248,113,113,0.1);
            color: var(--error);
        }

        .icon-btn:hover {
            transform: scale(1.1) rotate(10deg);
            background: rgba(102,126,234,0.2);
        }

        .icon-btn.danger:hover {
            background: rgba(248,113,113,0.2);
        }

        .icon-btn:active {
            transform: scale(0.95);
        }

        /* Messages Area */
        .messages-container {
            height: calc(var(--space-xxl) * 3);
            overflow-y: auto;
            margin-bottom: var(--space-l);
            padding: var(--space-xs);
            scrollbar-width: thin;
            scrollbar-color: var(--accent) transparent;
        }

        .messages-container::-webkit-scrollbar {
            width: calc(var(--space-xs) / 2);
        }

        .messages-container::-webkit-scrollbar-thumb {
            background: var(--accent);
            border-radius: calc(var(--border-radius-s) / 2);
        }

        .message {
            margin-bottom: var(--space-m);
            padding: var(--space-s) var(--space-m);
            border-radius: var(--border-radius-m);
            max-width: 85%;
            animation: slideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            word-wrap: break-word;
            line-height: var(--phi);
        }

        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(var(--space-s));
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .message.user {
            background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
            color: white;
            margin-left: auto;
            text-align: right;
            box-shadow: 0 var(--space-xs) var(--space-m) rgba(102,126,234,0.2);
        }

        .message.bot {
            background: rgba(102,126,234,0.08);
            border: 1px solid rgba(102,126,234,0.15);
        }

        .dark-mode .message.bot {
            background: rgba(102,126,234,0.12);
            border-color: rgba(102,126,234,0.25);
        }

        .message-sources {
            font-size: var(--text-xs);
            opacity: 0.7;
            margin-top: var(--space-xs);
            padding-top: var(--space-xs);
            border-top: 1px solid rgba(102,126,234,0.2);
            font-style: italic;
            display: flex;
            flex-wrap: wrap;
            gap: var(--space-xs);
        }

        .source-link {
            color: var(--accent);
            text-decoration: none;
            transition: all 0.2s;
            padding: var(--space-xxs) var(--space-xs);
            background: rgba(102,126,234,0.1);
            border-radius: var(--border-radius-s);
        }

        .source-link:hover {
            background: rgba(102,126,234,0.2);
            transform: translateY(-1px);
        }

        .read-sources-btn {
            font-size: var(--text-xs);
            padding: var(--space-xxs) var(--space-xs);
            border: 1px solid var(--accent);
            background: transparent;
            color: var(--accent);
            border-radius: var(--border-radius-s);
            cursor: pointer;
            transition: all 0.2s;
            margin-top: var(--space-xxs);
        }

        .read-sources-btn:hover {
            background: var(--accent);
            color: white;
        }

        /* Input Area */
        .input-area {
            display: flex;
            gap: var(--space-s);
            align-items: center;
        }

        .input-field {
            flex: 1;
            padding: var(--space-s) var(--space-m);
            border-radius: calc(var(--space-xxl));
            border: 2px solid transparent;
            background: rgba(102,126,234,0.08);
            font-size: var(--text-m);
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            outline: none;
            font-family: inherit;
            line-height: var(--phi);
        }

        .light-mode .input-field {
            color: var(--text-light);
        }

        .dark-mode .input-field {
            color: var(--text-dark);
        }

        .input-field::placeholder {
            opacity: 0.5;
        }

        .input-field:focus {
            border-color: var(--accent);
            background: rgba(102,126,234,0.12);
            box-shadow: 0 0 0 calc(var(--space-xs) / 2) rgba(102,126,234,0.1);
        }

        .action-btn {
            width: calc(var(--space-l) * var(--phi));
            height: calc(var(--space-l) * var(--phi));
            border-radius: 50%;
            border: none;
            background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
            color: white;
            cursor: pointer;
            display: grid;
            place-items: center;
            font-size: var(--text-l);
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            box-shadow: 0 var(--space-xs) var(--space-m) rgba(102,126,234,0.3);
        }

        .action-btn:hover {
            transform: translateY(calc(var(--space-xxs) * -1));
            box-shadow: 0 var(--space-s) var(--space-l) rgba(102,126,234,0.4);
        }

        .action-btn:active {
            transform: scale(0.95);
        }

        .action-btn.listening {
            animation: pulse 1.5s infinite;
        }

        @keyframes pulse {
            0%, 100% { transform: scale(1); }
            50% { transform: scale(1.15); }
        }

        /* Settings Overlay */
        .settings-overlay {
            position: fixed;
            inset: 0;
            background: rgba(0,0,0,0.6);
            backdrop-filter: blur(var(--space-xs));
            z-index: 999;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s ease;
        }

        .settings-overlay.active {
            opacity: 1;
            pointer-events: all;
        }

        /* Settings Panel */
        .settings-panel {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%) scale(0.9);
            width: min(calc(var(--chat-width) * 0.8), 90vw);
            max-height: 85vh;
            overflow-y: auto;
            padding: var(--space-xl);
            border-radius: var(--border-radius-l);
            backdrop-filter: blur(calc(var(--space-l) * var(--phi)));
            box-shadow: 0 var(--space-l) var(--space-xxl) rgba(0,0,0,0.3);
            z-index: 1000;
            opacity: 0;
            pointer-events: none;
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        }

        .settings-panel.active {
            opacity: 1;
            pointer-events: all;
            transform: translate(-50%, -50%) scale(1);
        }

        .light-mode .settings-panel {
            background: var(--card-light);
            border: 1px solid rgba(0,0,0,0.1);
        }

        .dark-mode .settings-panel {
            background: var(--card-dark);
            border: 1px solid rgba(255,255,255,0.15);
        }

        .settings-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: var(--space-xl);
            padding-bottom: var(--space-m);
            border-bottom: 2px solid rgba(102,126,234,0.2);
        }

        .settings-title {
            font-size: var(--text-l);
            font-weight: 800;
            background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }

        .close-btn {
            width: calc(var(--space-l) * var(--phi));
            height: calc(var(--space-l) * var(--phi));
            border-radius: 50%;
            border: none;
            background: rgba(248,113,113,0.1);
            color: var(--error);
            cursor: pointer;
            display: grid;
            place-items: center;
            font-size: var(--text-l);
            transition: all 0.2s;
        }

        .close-btn:hover {
            background: rgba(248,113,113,0.2);
            transform: scale(1.15) rotate(90deg);
        }

        .settings-section {
            margin-bottom: var(--space-l);
        }

        .section-title {
            font-size: var(--text-m);
            font-weight: 700;
            color: var(--accent);
            margin-bottom: var(--space-m);
            display: flex;
            align-items: center;
            gap: var(--space-s);
        }

        .setting-row {
            margin-bottom: var(--space-m);
        }

        .setting-label {
            display: block;
            font-size: var(--text-s);
            font-weight: 600;
            margin-bottom: var(--space-xs);
            opacity: 0.9;
        }

        .setting-description {
            font-size: var(--text-xs);
            opacity: 0.6;
            margin-bottom: var(--space-xs);
        }

        .setting-select,
        .setting-input {
            width: 100%;
            padding: var(--space-s) var(--space-m);
            border-radius: var(--border-radius-m);
            border: 1px solid rgba(102,126,234,0.2);
            background: rgba(102,126,234,0.08);
            font-size: var(--text-s);
            cursor: pointer;
            outline: none;
            font-family: inherit;
            transition: all 0.2s;
        }

        .light-mode .setting-select,
        .light-mode .setting-input {
            color: var(--text-light);
        }

        .dark-mode .setting-select,
        .dark-mode .setting-input {
            color: var(--text-dark);
        }

        .setting-select:hover,
        .setting-input:hover {
            border-color: var(--accent);
        }

        .setting-select:focus,
        .setting-input:focus {
            border-color: var(--accent);
            background: rgba(102,126,234,0.12);
        }

        .toggle-group {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(calc(var(--space-xxl) * 1.5), 1fr));
            gap: var(--space-xs);
        }

        .toggle-btn {
            padding: var(--space-s);
            border-radius: var(--border-radius-m);
            border: 2px solid transparent;
            background: rgba(102,126,234,0.08);
            cursor: pointer;
            transition: all 0.2s;
            font-weight: 600;
            font-size: var(--text-s);
            text-align: center;
        }

        .light-mode .toggle-btn {
            color: var(--text-light);
        }

        .dark-mode .toggle-btn {
            color: var(--text-dark);
        }

        .toggle-btn.active {
            border-color: var(--accent);
            background: rgba(102,126,234,0.2);
            color: var(--accent);
            transform: scale(1.02);
        }

        .toggle-btn:hover:not(.active) {
            background: rgba(102,126,234,0.15);
        }

        .checkbox-wrapper {
            display: flex;
            align-items: center;
            gap: var(--space-s);
            padding: var(--space-s);
            background: rgba(102,126,234,0.05);
            border-radius: var(--border-radius-m);
            cursor: pointer;
            transition: all 0.2s;
        }

        .checkbox-wrapper:hover {
            background: rgba(102,126,234,0.1);
        }

        .checkbox-wrapper input[type="checkbox"] {
            width: calc(var(--space-m) * var(--phi));
            height: calc(var(--space-m) * var(--phi));
            cursor: pointer;
        }

        .slider-container {
            display: flex;
            align-items: center;
            gap: var(--space-m);
        }

        .slider {
            flex: 1;
            height: var(--space-xs);
            border-radius: calc(var(--space-xs) / 2);
            background: rgba(102,126,234,0.2);
            outline: none;
            cursor: pointer;
        }

        .slider-value {
            min-width: calc(var(--space-xl));
            text-align: center;
            font-weight: 700;
            color: var(--accent);
        }

        /* Responsive */
        @media (max-width: 768px) {
            :root {
                --unit: 16px;
            }

            .chat-interface {
                padding: var(--space-m);
            }

            .settings-panel {
                padding: var(--space-l);
            }

            .toggle-group {
                grid-template-columns: 1fr;
            }
        }

        /* Accessibility */
        @media (prefers-reduced-motion: reduce) {
            *, *::before, *::after {
                animation-duration: 0.01ms !important;
                animation-iteration-count: 1 !important;
                transition-duration: 0.01ms !important;
            }
        }

        .sr-only {
            position: absolute;
            width: 1px;
            height: 1px;
            padding: 0;
            margin: -1px;
            overflow: hidden;
            clip: rect(0,0,0,0);
            white-space: nowrap;
            border: 0;
        }
    </style>
</head>
<body class="light-mode">
    <div class="chat-container">
        <article class="chat-interface">
            <header class="chat-header">
                <h1 class="chat-title">🧠 Curiosity</h1>
                <div class="header-actions">
                    <button class="icon-btn danger" onclick="clearConversation()" 
                            aria-label="Effacer" title="Effacer la conversation">🗑️</button>
                    <button class="icon-btn" onclick="openSettings()" 
                            aria-label="Paramètres" title="Paramètres">⚙️</button>
                </div>
            </header>

            <div id="messages" class="messages-container" role="log" aria-live="polite">
                <div class="message bot">
                    👋 <strong>Bonjour,</strong> Je suis Curiosity, votre oracle culturel français. 
                    <br>Posez-moi n'importe quelle question !
                </div>
            </div>

            <form class="input-area" onsubmit="event.preventDefault(); sendMessage();">
                <input type="text" id="inputField" class="input-field" 
                       placeholder="Posez votre question..." 
                       aria-label="Question">
                <button type="button" class="action-btn" id="micBtn" 
                        onclick="toggleVoice()" aria-label="Vocal">🎤</button>
                <button type="submit" class="action-btn" aria-label="Envoyer">▶️</button>
            </form>
        </article>
    </div>

    <!-- Settings Overlay -->
    <div class="settings-overlay" id="settingsOverlay" onclick="closeSettings()"></div>
    
    <!-- Settings Panel -->
    <aside class="settings-panel" id="settingsPanel" role="dialog" aria-modal="true">
        <header class="settings-header">
            <h2 class="settings-title">⚙️ Réglages Avancés</h2>
            <button class="close-btn" onclick="closeSettings()" aria-label="Fermer">✕</button>
        </header>

        <!-- SECTION: Apparence -->
        <section class="settings-section">
            <h3 class="section-title">🎨 Apparence</h3>
            
            <div class="setting-row">
                <label class="setting-label">Thème</label>
                <div class="setting-description">Choisissez le thème d'affichage</div>
                <div class="toggle-group">
                    <button class="toggle-btn" id="autoThemeBtn" onclick="setTheme('auto')">Auto</button>
                    <button class="toggle-btn active" id="lightThemeBtn" onclick="setTheme('light')">☀️ Clair</button>
                    <button class="toggle-btn" id="darkThemeBtn" onclick="setTheme('dark')">🌙 Sombre</button>
                </div>
            </div>

            <div class="setting-row">
                <label class="setting-label">Affichage du personnage</label>
                <div class="setting-description">Montrer/cacher Curiosity</div>
                <div class="checkbox-wrapper" onclick="toggleViewerDisplay(this)">
                    <input type="checkbox" id="showViewer" checked>
                    <label for="showViewer">Afficher le personnage Curiosity</label>
                </div>
            </div>

            <div class="setting-row">
                <label class="setting-label">Taille de la fenêtre</label>
                <div class="setting-description">Ajuster la taille selon vos préférences</div>
                <div class="slider-container">
                    <input type="range" class="slider" id="chatSize" min="0.8" max="1.5" step="0.1" value="1" 
                           oninput="updateChatSize(this.value)">
                    <span class="slider-value" id="chatSizeValue">100%</span>
                </div>
            </div>
        </section>

        <!-- SECTION: Voix -->
        <section class="settings-section">
            <h3 class="section-title">🎤 Synthèse Vocale</h3>
            
            <div class="setting-row">
                <label class="setting-label" for="voiceSelect">Voix française</label>
                <div class="setting-description">Sélectionnez la voix de lecture</div>
                <select id="voiceSelect" class="setting-select"></select>
            </div>

            <div class="setting-row">
                <label class="setting-label">Vitesse de lecture</label>
                <div class="slider-container">
                    <input type="range" class="slider" id="speechRate" min="0.5" max="2" step="0.1" value="1" 
                           oninput="updateSpeechRate(this.value)">
                    <span class="slider-value" id="speechRateValue">1.0x</span>
                </div>
            </div>

            <div class="setting-row">
                <div class="checkbox-wrapper" onclick="toggleAutoSpeak(this)">
                    <input type="checkbox" id="autoSpeak" checked>
                    <label for="autoSpeak">Lecture automatique des réponses</label>
                </div>
            </div>

            <div class="setting-row">
                <div class="checkbox-wrapper" onclick="toggleReadSources(this)">
                    <input type="checkbox" id="readSources">
                    <label for="readSources">Lire les sources à voix haute</label>
                </div>
            </div>
        </section>

        <!-- SECTION: Conversation -->
        <section class="settings-section">
            <h3 class="section-title">💬 Conversation</h3>
            
            <div class="setting-row">
                <label class="setting-label" for="modeSelect">Mode de réponse</label>
                <div class="setting-description">Longueur des réponses de Curiosity</div>
                <select id="modeSelect" class="setting-select">
                    <option value="concise">Concis (2 phrases)</option>
                    <option value="detailed">Détaillé (5 phrases)</option>
                    <option value="comprehensive">Complet (10+ phrases)</option>
                </select>
            </div>

            <div class="setting-row">
                <label class="setting-label">Historique conservé</label>
                <div class="setting-description">Nombre d'échanges mémorisés</div>
                <div class="slider-container">
                    <input type="range" class="slider" id="historySize" min="3" max="20" step="1" value="10" 
                           oninput="updateHistorySize(this.value)">
                    <span class="slider-value" id="historySizeValue">10</span>
                </div>
            </div>

            <div class="setting-row">
                <div class="checkbox-wrapper" onclick="togglePersistence(this)">
                    <input type="checkbox" id="persistence" checked>
                    <label for="persistence">Sauvegarder l'historique (localStorage)</label>
                </div>
            </div>
        </section>

        <!-- SECTION: Avancé -->
        <section class="settings-section">
            <h3 class="section-title">🔧 Avancé</h3>
            
            <div class="setting-row">
                <label class="setting-label" for="apiUrl">URL de l'API</label>
                <div class="setting-description">Ne modifiez que si nécessaire</div>
                <input type="text" id="apiUrl" class="setting-input" 
                       value="https://curiosity-silk.vercel.app/api/chat" 
                       placeholder="URL de l'API">
            </div>

            <div class="setting-row">
                <label class="setting-label">Délai d'affichage des yeux</label>
                <div class="setting-description">Durée d'affichage des recherches (secondes)</div>
                <div class="slider-container">
                    <input type="range" class="slider" id="eyesDelay" min="3" max="15" step="1" value="8" 
                           oninput="updateEyesDelay(this.value)">
                    <span class="slider-value" id="eyesDelayValue">8s</span>
                </div>
            </div>

            <div class="setting-row">
                <div class="checkbox-wrapper" onclick="toggleParallax(this)">
                    <input type="checkbox" id="parallax" checked>
                    <label for="parallax">Effet parallax sur le personnage</label>
                </div>
            </div>

            <div class="setting-row">
                <div class="checkbox-wrapper" onclick="toggleDebug(this)">
                    <input type="checkbox" id="debug">
                    <label for="debug">Mode debug (console)</label>
                </div>
            </div>
        </section>

        <button class="action-btn" style="width: 100%; border-radius: var(--border-radius-m); margin-top: var(--space-l);" 
                onclick="saveSettings()">
            💾 Sauvegarder les paramètres
        </button>
    </aside>

    <script>
        const API_URL = 'https://curiosity-silk.vercel.app/api/chat';
        
        let config = {
            theme: 'light',
            showViewer: true,
            chatSize: 1,
            speechRate: 1,
            autoSpeak: true,
            readSources: false,
            mode: 'concise',
            historySize: 10,
            persistence: true,
            apiUrl: API_URL,
            eyesDelay: 8,
            parallax: true,
            debug: false
};
let recognition, isListening = false, history = [], voices = [], selectedVoice;
    let viewerWindow = null;

    // ============================================
    // INIT & PERSISTENCE
    // ============================================
    function loadSettings() {
        try {
            const saved = localStorage.getItem('curiosity-config');
            if (saved) {
                config = { ...config, ...JSON.parse(saved) };
                applySettings();
            }
        } catch (e) {
            console.warn('Could not load settings:', e);
        }
    }

    function saveSettings() {
        try {
            localStorage.setItem('curiosity-config', JSON.stringify(config));
            alert('✅ Paramètres sauvegardés !');
            applySettings();
        } catch (e) {
            console.error('Could not save settings:', e);
            alert('❌ Erreur lors de la sauvegarde');
        }
    }

    function applySettings() {
        // Thème
        setTheme(config.theme);
        
        // Taille chat
        updateChatSize(config.chatSize);
        document.getElementById('chatSize').value = config.chatSize;
        
        // Voix
        document.getElementById('speechRate').value = config.speechRate;
        document.getElementById('speechRateValue').textContent = config.speechRate + 'x';
        
        // Checkboxes
        document.getElementById('autoSpeak').checked = config.autoSpeak;
        document.getElementById('readSources').checked = config.readSources;
        document.getElementById('persistence').checked = config.persistence;
        document.getElementById('showViewer').checked = config.showViewer;
        document.getElementById('parallax').checked = config.parallax;
        document.getElementById('debug').checked = config.debug;
        
        // Selects
        document.getElementById('modeSelect').value = config.mode;
        document.getElementById('apiUrl').value = config.apiUrl;
        
        // Sliders
        document.getElementById('historySize').value = config.historySize;
        document.getElementById('historySizeValue').textContent = config.historySize;
        document.getElementById('eyesDelay').value = config.eyesDelay;
        document.getElementById('eyesDelayValue').textContent = config.eyesDelay + 's';
    }

    function loadConversation() {
        if (!config.persistence) return;
        
        try {
            const savedHistory = localStorage.getItem('curiosity-history');
            const savedMessages = localStorage.getItem('curiosity-messages');
            
            if (savedHistory) {
                history = JSON.parse(savedHistory);
            }
            
            if (savedMessages) {
                document.getElementById('messages').innerHTML = savedMessages;
            }
        } catch (e) {
            if (config.debug) console.warn('Could not load conversation:', e);
        }
    }

    function saveConversation() {
        if (!config.persistence) return;
        
        try {
            localStorage.setItem('curiosity-history', JSON.stringify(history));
            localStorage.setItem('curiosity-messages', document.getElementById('messages').innerHTML);
        } catch (e) {
            if (config.debug) console.warn('Could not save conversation:', e);
        }
    }

    function clearConversation() {
        if (confirm('Effacer toute la conversation ?')) {
            history = [];
            localStorage.removeItem('curiosity-history');
            localStorage.removeItem('curiosity-messages');
            
            document.getElementById('messages').innerHTML = `
                <div class="message bot">
                    👋 <strong>Bonjour !</strong> Je suis Curiosity, votre oracle français. Météo, heure, Bitcoin, recettes, histoire... Posez-moi n'importe quelle question !
                </div>
            `;
        }
    }

    // ============================================
    // THEME
    // ============================================
    function detectTheme() {
        return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    }

    function setTheme(mode) {
        config.theme = mode;
        document.querySelectorAll('.toggle-btn').forEach(b => b.classList.remove('active'));
        document.getElementById(mode + 'ThemeBtn').classList.add('active');
        document.body.className = (mode === 'auto' ? detectTheme() : mode) + '-mode';
    }

    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
        if(config.theme === 'auto') setTheme('auto');
    });

    // ============================================
    // VOICE RECOGNITION
    // ============================================
    if('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) {
        const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
        recognition = new SR();
        recognition.lang = 'fr-FR';
        recognition.onresult = e => {
            document.getElementById('inputField').value = e.results[0][0].transcript;
            sendMessage();
        };
        recognition.onend = () => stopListening();
    }

    function toggleVoice() {
        if(!recognition) return alert('❌ Non supporté');
        isListening ? stopListening() : startListening();
    }

    function startListening() {
        isListening = true;
        document.getElementById('micBtn').classList.add('listening');
        recognition.start();
    }

    function stopListening() {
        isListening = false;
        document.getElementById('micBtn').classList.remove('listening');
        if(recognition) recognition.stop();
    }

    // ============================================
    // VOICE SYNTHESIS
    // ============================================
    function loadVoices() {
        voices = speechSynthesis.getVoices().filter(v => v.lang.startsWith('fr'));
        const sel = document.getElementById('voiceSelect');
        sel.innerHTML = '';
        voices.forEach((v, i) => {
            const opt = document.createElement('option');
            opt.value = i;
            opt.textContent = `${v.name} (${v.lang})`;
            sel.appendChild(opt);
        });
        const pref = voices.findIndex(v => v.name.includes('Thomas') || v.name.includes('French'));
        if(pref !== -1) {
            sel.value = pref;
            selectedVoice = voices[pref];
        }
    }

    speechSynthesis.onvoiceschanged = loadVoices;
    loadVoices();
    document.getElementById('voiceSelect').onchange = e => selectedVoice = voices[e.target.value];

    function cleanTextForSpeech(text) {
        // Supprimer les caractères markdown: ** // _ ~~
        return text
            .replace(/\*\*/g, '')
            .replace(/\*/g, '')
            .replace(/\_\_/g, '')
            .replace(/\_/g, '')
            .replace(/\~\~/g, '')
            .replace(/\`\`\`/g, '')
            .replace(/\`/g, '')
            .replace(/\#\#\#/g, '')
            .replace(/\#\#/g, '')
            .replace(/\#/g, '')
            .replace(/\//g, '')
            .trim();
    }

    function speak(text, includeSources = false) {
        if (!config.autoSpeak) return;
        if (!('speechSynthesis' in window)) return;

        const cleanText = cleanTextForSpeech(text);
        
        const utterance = new SpeechSynthesisUtterance(cleanText);
        utterance.lang = 'fr-FR';
        utterance.rate = config.speechRate;
        utterance.pitch = 1.0;
        if(selectedVoice) utterance.voice = selectedVoice;
        
        speechSynthesis.speak(utterance);
    }

    function speakSources(sources) {
        if (!config.readSources || !sources || !sources.length) return;
        
        const sourcesText = `Sources consultées: ${sources.map((s, i) => {
            const domain = s.match(/https?:\/\/([^\/]+)/)?.[1] || s;
            return `source ${i + 1}: ${domain}`;
        }).join(', ')}`;
        
        setTimeout(() => {
            speak(sourcesText);
        }, 1000);
    }

    // ============================================
    // VIEWER COMMUNICATION
    // ============================================
    function sendToViewer(action, data) {
        if (!config.showViewer) return;
        
        // Si viewer dans iframe
        const viewerFrame = parent.document.querySelector('#curiosity-viewer');
        if (viewerFrame && viewerFrame.contentWindow) {
            viewerFrame.contentWindow.postMessage({ action, data }, '*');
        }
        
        // Si viewer dans window séparée
        if (viewerWindow && !viewerWindow.closed) {
            viewerWindow.postMessage({ action, data }, '*');
        }
    }

    // ============================================
    // MESSAGES
    // ============================================
    function addMsg(text, type, sources) {
        const msgs = document.getElementById('messages');
        const div = document.createElement('div');
        div.className = `message ${type}`;
        let html = text;
        
        if(sources?.length) {
            const sourceLinks = sources.map((s, i) => {
                const domain = s.match(/https?:\/\/([^\/]+)/)?.[1] || `Source ${i + 1}`;
                return `<a href="${s}" class="source-link" target="_blank" rel="noopener">${domain}</a>`;
            }).join('');
            
            html += `<div class="message-sources">
                📚 ${sourceLinks}
                ${!config.readSources ? '<button class="read-sources-btn" onclick="speakSources(' + JSON.stringify(sources) + ')">🔊 Lire les sources</button>' : ''}
            </div>`;
        }
        
        div.innerHTML = html;
        msgs.appendChild(div);
        msgs.scrollTop = msgs.scrollHeight;
        
        saveConversation();
    }

    // ============================================
    // SEND MESSAGE
    // ============================================
    async function sendMessage() {
        const input = document.getElementById('inputField');
        const msg = input.value.trim();
        if(!msg) return;

        addMsg(msg, 'user');
        history.push({role: 'user', content: msg});
        if(history.length > config.historySize * 2) {
            history = history.slice(-config.historySize * 2);
        }
        input.value = '';

        // Viewer
        sendToViewer('setState', 'THINKING');
        sendToViewer('setStatus', 'thinking');
        sendToViewer('showCode', msg);

        try {
            const maxSentences = config.mode === 'concise' ? 2 : config.mode === 'detailed' ? 5 : 10;
            
            const res = await fetch(config.apiUrl, {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({
                    question: msg,
                    max_sentences: maxSentences,
                    history: history.slice(-config.historySize)
                })
            });

            if(!res.ok) throw new Error();

            const data = await res.json();
            history.push({role: 'assistant', content: data.answer});

            addMsg(data.answer, 'bot', data.sources);

            // Aperçu dans l'œil droit
            if (data.sources && data.sources.length > 0) {
                sendToViewer('showPreview', data.sources[0]);
                
                setTimeout(() => {
                    sendToViewer('clearEyes');
                }, config.eyesDelay * 1000);
            }

            // Lecture vocale
            speak(data.answer);
            if (config.readSources) {
                speakSources(data.sources);
            }

            // Viewer
            sendToViewer('setState', 'GOOD');
            sendToViewer('setStatus', '');

        } catch(err) {
            if (config.debug) console.error(err);
            addMsg('❌ Erreur. Réessayez.', 'bot');
            sendToViewer('setState', 'BAD');
            sendToViewer('setStatus', 'error');
            sendToViewer('clearEyes');
        }
    }

    // ============================================
    // SETTINGS
    // ============================================
    function openSettings() {
        document.getElementById('settingsPanel').classList.add('active');
        document.getElementById('settingsOverlay').classList.add('active');
    }

    function closeSettings() {
        document.getElementById('settingsPanel').classList.remove('active');
        document.getElementById('settingsOverlay').classList.remove('active');
    }

    function updateChatSize(value) {
        config.chatSize = parseFloat(value);
        document.getElementById('chatSizeValue').textContent = Math.round(value * 100) + '%';
        document.documentElement.style.setProperty('--chat-width', `${600 * value}px`);
    }

    function updateSpeechRate(value) {
        config.speechRate = parseFloat(value);
        document.getElementById('speechRateValue').textContent = value + 'x';
    }

    function updateHistorySize(value) {
        config.historySize = parseInt(value);
        document.getElementById('historySizeValue').textContent = value;
    }

    function updateEyesDelay(value) {
        config.eyesDelay = parseInt(value);
        document.getElementById('eyesDelayValue').textContent = value + 's';
    }

    function toggleViewerDisplay(wrapper) {
        config.showViewer = wrapper.querySelector('input').checked;
    }

    function toggleAutoSpeak(wrapper) {
        config.autoSpeak = wrapper.querySelector('input').checked;
    }

    function toggleReadSources(wrapper) {
        config.readSources = wrapper.querySelector('input').checked;
    }

    function togglePersistence(wrapper) {
        config.persistence = wrapper.querySelector('input').checked;
    }

    function toggleParallax(wrapper) {
        config.parallax = wrapper.querySelector('input').checked;
        sendToViewer('toggleParallax', config.parallax);
    }

    function toggleDebug(wrapper) {
        config.debug = wrapper.querySelector('input').checked;
    }

    // ============================================
    // INIT
    // ============================================
    loadSettings();
    loadConversation();
    setTheme(config.theme);

    // Initialiser le viewer
    sendToViewer('setState', 'OFF');
    setTimeout(() => {
        sendToViewer('setState', 'ON');
        sendToViewer('setStatus', '');
    }, 1000);
</script>
</body>
</html>				</div>
				</div>
					</div>
				</div>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/curiosity/">Curiosity</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>SPLATGATE⟶⦗⦘</title>
		<link>https://presentcomposedesign.fr/splatgate/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 15 Nov 2025 10:19:01 +0000</pubDate>
				<category><![CDATA[[ia]]]></category>
		<category><![CDATA[[VR]]]></category>
		<category><![CDATA[Design d'espace]]></category>
		<category><![CDATA[Design produit]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=34089</guid>

					<description><![CDATA[<p>Embarquez pour un voyage immersif inédit avec SPLAT‎GATE, le portail WebXR de Présent Composé Design. Alliant la puissance du Gaussian Splatting à une accessibilité totale sans application, ce hub redéfinit l'exploration spatiale directement depuis votre navigateur. Découvrez notre candidature officielle pour le prix international #SplatOfTheYear aux #ThePolys et soutenez l'innovation française dans le futur du web 3D.</p>
<p>Cet article <a href="https://presentcomposedesign.fr/splatgate/">SPLATGATE⟶⦗⦘</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="34089" class="elementor elementor-34089">
						<section class="elementor-section elementor-top-section elementor-element elementor-element-e54cb28 elementor-section-full_width elementor-section-height-min-height elementor-section-items-bottom elementor-section-content-middle elementor-section-stretched elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="e54cb28" data-element_type="section" data-e-type="section" data-settings="{&quot;stretch_section&quot;:&quot;section-stretched&quot;,&quot;background_background&quot;:&quot;classic&quot;}">
						<div class="elementor-container elementor-column-gap-extended">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-d602f2f" data-id="d602f2f" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-4fd7d3a elementor-widget__width-inherit elementor-widget elementor-widget-html" data-id="4fd7d3a" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<style>
    /* Section plein écran sans aucune bordure ou marge parasite */
    .splatgate-hero-video-only {
        position: relative;
        width: 100%;
        height: 70vh; /* Remplit 100% de la hauteur de la fenêtre */
        margin: 0;
        padding: 0;
        overflow: hidden;
        background-color: #000; /* Fond noir de secours */
    }

    /* La vidéo s'adapte parfaitement à tout l'espace disponible */
    .hero-video-full {
        width: 100%;
        height: 100%;
        object-fit: cover; /* Garantit que la vidéo couvre tout l'espace sans déformation */
        display: block;
    }

    /* Ajustement de la hauteur pour le mobile si besoin d'apercevoir le titre dessous */
    @media (max-width: 768px) {
        .splatgate-hero-video-only {
            height: 70vh; /* Permet de voir le début du titre suivant sur un petit écran */
        }
    }
</style>

<section class="splatgate-hero-video-only">
    <video 
        autoplay 
        muted 
        loop 
        playsinline 
        class="hero-video-full">
        <source src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/video_presentation_SPLATGATE_PresentComposedesign-2025.mp4" type="video/mp4">
        Votre navigateur ne supporte pas la lecture de vidéos.
    </video>
</section>				</div>
				</div>
				<section class="elementor-section elementor-inner-section elementor-element elementor-element-14759a4 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="14759a4" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-43ed930" data-id="43ed930" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-8fda2db splatgate-title elementor-widget elementor-widget-heading" data-id="8fda2db" data-element_type="widget" data-e-type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
					<h1 class="elementor-heading-title elementor-size-default">SPLATGATE ⟶⦗⦘</h1>				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-5705354 elementor-section-full_width elementor-section-height-min-height elementor-section-items-bottom elementor-section-content-middle elementor-section-stretched elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no elementor-invisible" data-id="5705354" data-element_type="section" data-e-type="section" data-settings="{&quot;stretch_section&quot;:&quot;section-stretched&quot;,&quot;background_background&quot;:&quot;classic&quot;,&quot;animation&quot;:&quot;fadeInUp&quot;}">
						<div class="elementor-container elementor-column-gap-extended">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-85a3763" data-id="85a3763" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<section class="elementor-section elementor-inner-section elementor-element elementor-element-2ea17bf elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="2ea17bf" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-fa870ea" data-id="fa870ea" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-d894641 elementor-widget elementor-widget-image" data-id="d894641" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img fetchpriority="high" decoding="async" width="1000" height="1000" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square.jpg" class="attachment-full size-full wp-image-35342" alt="Visuel présentation Splatgate" srcset="https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square.jpg 1000w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square-300x300.jpg 300w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square-150x150.jpg 150w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square-768x768.jpg 768w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square-600x600.jpg 600w" sizes="(max-width: 1000px) 100vw, 1000px" />															</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-dd36fbf" data-id="dd36fbf" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-9570f92 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="9570f92" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<p><style>
    .emoji-container {<br />        display: inline-block;<br />        width: 0.8em; /* Taille du conteneur ajustée pour mieux voir l'effet */<br />        height: 0.8em;<br />        margin-right: 0.2em;<br />        position: relative;<br />        background: linear-gradient(45deg, #ff00ff, #00ffff, #ff00ff); /* Dégradé à 45 degrés */<br />        border-radius: 50%;<br />        vertical-align: middle;<br />        animation: colorchange 6s infinite;<br />    }</p>
<p>    .inner-circle {<br />        width: 50%; /* Taille du cercle blanc par rapport au conteneur */<br />        height: 20%;<br />        border-radius: 50%;<br />        background-color: white;<br />        position: relative;<br />        top: 50%; /* Ajuste la position verticale pour centrer */<br />        left: 50%; /* Ajuste la position horizontale pour centrer */<br />        animation: rotate 20s linear infinite; /* Animation de rotation */<br />        transform-origin: center center; /* Point de rotation au centre */<br />    }</p>
<p>    @keyframes colorchange {<br />        0% { filter: hue-rotate(0deg); }<br />        100% { filter: hue-rotate(360deg); }<br />    }</p>
<p>    @keyframes rotate {<br />        0% { transform: translate(-50%, -50%) rotate(0deg); }<br />        100% { transform: translate(-50%, -50%) rotate(360deg); }<br />    }<br /></style></p><div class="inner-circle"> </div><h1><span style="color: #0010ef;">Votre passeport VR pour ailleurs</span><span style="color: #0010ef; font-size: 16px;"> </span></h1><div class="vce-row-container" data-vce-boxed-width="true"><div id="el-ba3f564d" class="vce-row vce-row--col-gap-30 vce-row-equal-height vce-row-content--top" data-vce-do-apply="all el-ba3f564d"><div class="vce-row-content" data-vce-element-content="true"><div id="el-11f4390c" class="vce-col vce-col--md-auto vce-col--xs-1 vce-col--xs-last vce-col--xs-first vce-col--sm-last vce-col--sm-first vce-col--md-last vce-col--lg-last vce-col--xl-last vce-col--md-first vce-col--lg-first vce-col--xl-first"><div class="vce-col-inner" data-vce-do-apply="border margin background el-11f4390c"><div class="vce-col-content" data-vce-element-content="true" data-vce-do-apply="padding el-11f4390c"><div class="vce-google-fonts-heading vce-google-fonts-heading--align-left vce-google-fonts-heading--color-b-0-16-255--45--5C00FF--FF7200 vce-google-fonts-heading--font-family-Roboto"><div id="el-6e30c05c" class="vce-google-fonts-heading-wrapper"><div><span style="color: #0010ef;"> </span></div><div><p><span style="color: #0010ef;">SPLATGATE ⟶⦗⦘ n’est pas un jeu : c’est un portail.</span></p></div><h2><span style="color: #000000;">Ce hub immersif vous permet d’explorer des paysages réalistes en réalité virtuelle depuis votre ordinateur, votre smartphone ou votre casque XR.<br data-start="350" data-end="353" /><br />Installez‑vous confortablement, mettez votre casque (ou utilisez l’interface en version bureau, tablette ou téléphone) et laissez‑vous transporter vers des destinations d’exception.</span></h2><p>« Voyagez » seul pour vous ressourcer ou partagez l’expérience entre amis ; l’accès est gratuit et illimité.</p></div></div><div class="vce-text-block"><div id="el-93e454cf" class="vce-text-block-wrapper vce" data-vce-do-apply="all el-93e454cf" data-vce-animate="vce-o-animate--fadeInDown"> </div></div></div></div></div></div></div></div><div class="vce-row-container" data-vce-boxed-width="true"><div id="el-d9d9a9fd" class="vce-row vce-row--col-gap-30 vce-row-equal-height vce-row-content--top" data-vce-do-apply="all el-d9d9a9fd"><div class="vce-row-content" data-vce-element-content="true"><div id="el-87440d41" class="vce-col vce-col--md-auto vce-col--xs-1 vce-col--xs-last vce-col--xs-first vce-col--sm-last vce-col--sm-first vce-col--md-last vce-col--lg-last vce-col--xl-last vce-col--md-first vce-col--lg-first vce-col--xl-first"><div class="vce-col-inner" data-vce-do-apply="border margin background el-87440d41"><div class="vce-col-content" data-vce-element-content="true" data-vce-do-apply="padding el-87440d41"><p><!-- /wp:vcwb/empty-comment-element-wrapper --></p></div></div></div><p><!-- /vcwb/dynamicElementComment:87440d41 --></p></div></div></div><p><!-- /vcwb/dynamicElementComment:d9d9a9fd --><!--vcv no format--></p>								</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
		<div class="wpr-jarallax elementor-element elementor-element-5fe6ffb e-con-full wpr-jarallax-yes e-flex wpr-particle-no wpr-sticky-section-no e-con e-parent" speed-data="1.4" bg-image="https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025-2_2553x1594.jpg" scroll-effect="scroll" data-id="5fe6ffb" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;classic&quot;}">
				<div class="elementor-element elementor-element-8ce9abf elementor-widget elementor-widget-spacer" data-id="8ce9abf" data-element_type="widget" data-e-type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
							<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
						</div>
				</div>
				</div>
		<div class="elementor-element elementor-element-c8759f0 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no elementor-invisible e-con e-parent" data-id="c8759f0" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;classic&quot;,&quot;animation&quot;:&quot;slideInRight&quot;}">
					<div class="e-con-inner">
				<div class="elementor-element elementor-element-86a7112 elementor-arrows-position-outside elementor-pagination-position-outside elementor-widget elementor-widget-image-carousel" data-id="86a7112" data-element_type="widget" data-e-type="widget" data-settings="{&quot;slides_to_show&quot;:&quot;3&quot;,&quot;autoplay_speed&quot;:1800,&quot;speed&quot;:350,&quot;slides_to_scroll&quot;:&quot;1&quot;,&quot;image_spacing_custom&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:100,&quot;sizes&quot;:[]},&quot;navigation&quot;:&quot;both&quot;,&quot;autoplay&quot;:&quot;yes&quot;,&quot;pause_on_hover&quot;:&quot;yes&quot;,&quot;pause_on_interaction&quot;:&quot;yes&quot;,&quot;infinite&quot;:&quot;yes&quot;,&quot;image_spacing_custom_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;image_spacing_custom_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}" data-widget_type="image-carousel.default">
				<div class="elementor-widget-container">
							<div class="elementor-image-carousel-wrapper swiper" role="region" aria-roledescription="carousel" aria-label="Carrousel d’images" dir="ltr">
			<div class="elementor-image-carousel swiper-wrapper" aria-live="off">
								<div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="1 sur 5"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/Broceliande-Present-Compose-design-360-600x600.png" alt="Vue 360° forêt Brocéliande avec cercle de pierres, immersion en réalité virtuelle, Présent Composé design pour_SPLATGATE ⟶⦗⦘" /><figcaption class="elementor-image-carousel-caption">Broceliande ⟶⦗⦘</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="2 sur 5"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/GRAND-CANYON-Present-Compose-design-HD-360-600x600.png" alt="Vue 360° Grand Canyon réaliste en réalité virtuelle, lumière naturelle filtrée, Présent Composé design pour SPLATGATE ⟶⦗⦘" /><figcaption class="elementor-image-carousel-caption">GRAND-CANYON ⟶⦗⦘</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="3 sur 5"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/Rail-Road_Present-Compose-design-360-600x600.png" alt="Vue 360° de rails enneigés sous un ciel orageux, voyage virtuel SPLATGATE ⟶⦗⦘ Présent Composé design" /><figcaption class="elementor-image-carousel-caption">Rail-Road ⟶⦗⦘</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="4 sur 5"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/SALAR-DE-UYUNI-Present-Compose-design-360-600x600.png" alt="Vue 360° du Salar d’Uyuni, désert de sel sous ciel bleu, Présent Composé design pour SPLATGATE ⟶⦗⦘" /><figcaption class="elementor-image-carousel-caption">SALAR DE UYUNI ⟶⦗⦘</figcaption></figure></div><div class="swiper-slide" role="group" aria-roledescription="slide" aria-label="5 sur 5"><figure class="swiper-slide-inner"><img decoding="async" class="swiper-slide-image" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/Zhangjiajie-Present-Compose-design-360-600x600.png" alt="Panorama 360° du parc national de Zhangjiajie en Chine, imposants pitons rocheux inspirant Avatar" /><figcaption class="elementor-image-carousel-caption">Zhangjiajie⟶⦗⦘</figcaption></figure></div>			</div>
												<div class="elementor-swiper-button elementor-swiper-button-prev" role="button" tabindex="0">
						<svg aria-hidden="true" class="e-font-icon-svg e-eicon-chevron-left" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg"><path d="M646 125C629 125 613 133 604 142L308 442C296 454 292 471 292 487 292 504 296 521 308 533L604 854C617 867 629 875 646 875 663 875 679 871 692 858 704 846 713 829 713 812 713 796 708 779 692 767L438 487 692 225C700 217 708 204 708 187 708 171 704 154 692 142 675 129 663 125 646 125Z"></path></svg>					</div>
					<div class="elementor-swiper-button elementor-swiper-button-next" role="button" tabindex="0">
						<svg aria-hidden="true" class="e-font-icon-svg e-eicon-chevron-right" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg"><path d="M696 533C708 521 713 504 713 487 713 471 708 454 696 446L400 146C388 133 375 125 354 125 338 125 325 129 313 142 300 154 292 171 292 187 292 204 296 221 308 233L563 492 304 771C292 783 288 800 288 817 288 833 296 850 308 863 321 871 338 875 354 875 371 875 388 867 400 854L696 533Z"></path></svg>					</div>
				
									<div class="swiper-pagination"></div>
									</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-63d407d elementor-widget elementor-widget-spacer" data-id="63d407d" data-element_type="widget" data-e-type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
							<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
						</div>
				</div>
					</div>
				</div>
				<header class="elementor-section elementor-top-section elementor-element elementor-element-4c148bf elementor-section-full_width elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="4c148bf" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-no">
					<header class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3c33b84" data-id="3c33b84" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-778d960 elementor-widget__width-inherit elementor-widget elementor-widget-html" data-id="778d960" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<div class="splatgate-container">
    <!-- Iframe Arrival Space -->
    <iframe
        id="arrival-space-iframe"
        src="https://arrival.space/VR_Xprmnts?utm=embed_82998375"
        width="100%"
        height="860"
        allow="camera; microphone; vr; xr; fullscreen"
        allowfullscreen>
    </iframe>

    <!-- Conteneur pour les boutons -->
    <div class="buttons-container">
        <!-- Bloc de texte centré au-dessus du bouton VR -->
        <div class="vr-instruction-text">
            Click here 🡡 from your VR headset
        </div>

        <!-- Bouton VR (centré en haut) -->
        <a
            href="https://arrival.space/VR_Xprmnts"
            target="_blank"
            class="vr-direct-link vr-button"
        >
            SplatGate⟶⦗⦘ in VR ᯅ
        </a>

        <!-- Bouton Plein écran (bas à droite) -->
        <a
            id="fullscreen-link"
            class="vr-direct-link fullscreen-button"
        >
            Plein écran 🗖
        </a>
    </div>
</div>

<style>
    .splatgate-container {
        position: relative;
        width: 100vw;
        max-width: 100%;
        margin: 0;
        padding: 0;
        height: 860px;
        overflow: hidden;
    }

    .buttons-container {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        pointer-events: none;
    }

    .vr-instruction-text {
        position: absolute;
        top: 64px;
        left: 50%;
        transform: translateX(-50%);
        color: white;
        font-size: 14px;
        text-align: center;
        z-index: 1001;
        text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
        pointer-events: auto;
    }

    .vr-direct-link {
        position: absolute;
        padding: 8px 15px;
        background: #FF00FF;
        color: white;
        text-decoration: none;
        font-weight: bold;
        font-size: 14px;
        border-radius: 8px;
        border: 2px solid white;
        box-shadow: 0 0 8px rgba(255, 0, 255, 0.7);
        z-index: 1000;
        pointer-events: auto;
        cursor: pointer;
        transition: all 0.3s;
        font-family: sans-serif;
    }

    .vr-button {
        top: 16px;
        left: 50%;
        transform: translateX(-50%);
    }

    .fullscreen-button {
        bottom: 20px;
        right: 20px;
    }

    .vr-direct-link:hover {
        background: #FF69B4;
        box-shadow: 0 0 12px rgba(255, 0, 255, 0.9);
        z-index: 1001 !important;
    }

    #arrival-space-iframe {
        border: none;
        display: block;
        width: 100vw;
        margin: 0;
    }
</style>

<script>
    // Gestion du bouton Plein écran
    document.getElementById('fullscreen-link').addEventListener('click', function(e) {
        e.preventDefault();
        const iframe = document.getElementById('arrival-space-iframe');
        if (iframe.requestFullscreen) iframe.requestFullscreen();
        else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen();
        else if (iframe.msRequestFullscreen) iframe.msRequestFullscreen();
    });
</script>
				</div>
				</div>
					</div>
		</header>
					</div>
		</header>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-de33bb3 elementor-section-height-min-height elementor-section-items-bottom elementor-section-content-middle elementor-section-stretched elementor-section-boxed elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="de33bb3" data-element_type="section" data-e-type="section" data-settings="{&quot;stretch_section&quot;:&quot;section-stretched&quot;,&quot;background_background&quot;:&quot;classic&quot;}">
						<div class="elementor-container elementor-column-gap-extended">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-87ce8ad" data-id="87ce8ad" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<section class="elementor-section elementor-inner-section elementor-element elementor-element-0da3fca elementor-section-full_width elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="0da3fca" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-797121e" data-id="797121e" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-5ab8be5 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="5ab8be5" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h1 style="color: #ffffff;">Des destinations à couper le souffle</h1><div data-vce-boxed-width="true"><div data-vce-do-apply="all el-ba3f564d"><div data-vce-element-content="true"><div data-vce-do-apply="border margin background el-11f4390c"><div data-vce-element-content="true" data-vce-do-apply="padding el-11f4390c"><h2 style="color: #ffffff;">Depuis le hall principal, 5 portes vous invitent à la découverte :</h2><h3 style="color: #ffffff;">Brocéliande : plongez au cœur de la mythique forêt bretonne. Ruisseaux chantants, arbres centenaires et clairières lumineuses vous attendent dans cette reconstitution 3D fidèle à l’esprit des légendes arthuriennes.</h3><h3 style="color: #ffffff;">Grand Canyon : admirez les falaises orangées, les gorges vertigineuses et les jeux de lumière du sud-ouest américain. La visite en VR vous permet d’appréhender l’échelle monumentale de ce site emblématique sans prendre l’avion.</h3><h3 style="color: #ffffff;">Salar d’Uyuni : marchez sur un miroir naturel géant en Bolivie. Ce désert de sel offre un horizon infini où ciel et terre se confondent, réinterprété ici en 360° pour vous procurer une sensation de liberté absolue.<br /><br />&#8230;</h3><h2 style="color: #ffffff;">Chaque univers a été sculpté dans un moteur graphique réaliste et optimisé pour la VR. Les textures, les sons d’ambiance et la profondeur des décors vous plongent dans une escapade dépaysante tout en restant chez vous. Revenez régulièrement : de nouvelles destinations sont en préparation.</h2><h6><a style="color: #ffffff; text-decoration: underline;" href="https://arrival.space/VR_Xprmnts">https://arrival.space/VR_Xprmnts</a></h6><h2 style="color: #ffffff; font-variant-ligatures: normal; font-variant-caps: normal; font-family: 'Inter Tight', sans-serif; font-style: normal; font-weight: 400;">Conception &amp; réalisation : <em style="font-size: 20px;">VR_Xprmnts, Présent Composé Design &#8211; 2025</em></h2></div></div></div></div></div>								</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-1738006" data-id="1738006" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-87f2b39 elementor-invisible elementor-widget elementor-widget-image" data-id="87f2b39" data-element_type="widget" data-e-type="widget" data-settings="{&quot;_animation&quot;:&quot;zoomIn&quot;}" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img decoding="async" width="768" height="384" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/SALAR-DE-UYUNI-Present-Compose-design-360-768x384.png" class="attachment-medium_large size-medium_large wp-image-34236" alt="Vue 360° du Salar d’Uyuni, désert de sel sous ciel bleu, Présent Composé design pour SPLATGATE ⟶⦗⦘" srcset="https://presentcomposedesign.fr/wp-content/uploads/2025/11/SALAR-DE-UYUNI-Present-Compose-design-360-768x384.png 768w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SALAR-DE-UYUNI-Present-Compose-design-360-300x150.png 300w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SALAR-DE-UYUNI-Present-Compose-design-360-1920x960.png 1920w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SALAR-DE-UYUNI-Present-Compose-design-360-1536x768.png 1536w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SALAR-DE-UYUNI-Present-Compose-design-360-2048x1024.png 2048w" sizes="(max-width: 768px) 100vw, 768px" />															</div>
				</div>
				<div class="elementor-element elementor-element-e71b66e elementor-invisible elementor-widget elementor-widget-image" data-id="e71b66e" data-element_type="widget" data-e-type="widget" data-settings="{&quot;_animation&quot;:&quot;zoomIn&quot;}" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img decoding="async" width="600" height="600" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/Broceliande-Present-Compose-design-360-600x600.png" class="attachment-ocean-thumb-m size-ocean-thumb-m wp-image-34233" alt="Vue 360° forêt Brocéliande avec cercle de pierres, immersion en réalité virtuelle, Présent Composé design pour_SPLATGATE ⟶⦗⦘" srcset="https://presentcomposedesign.fr/wp-content/uploads/2025/11/Broceliande-Present-Compose-design-360-600x600.png 600w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/Broceliande-Present-Compose-design-360-150x150.png 150w" sizes="(max-width: 600px) 100vw, 600px" />															</div>
				</div>
				<div class="elementor-element elementor-element-4275f24 elementor-invisible elementor-widget elementor-widget-image" data-id="4275f24" data-element_type="widget" data-e-type="widget" data-settings="{&quot;_animation&quot;:&quot;zoomIn&quot;}" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="2048" height="1024" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/GRAND-CANYON-Present-Compose-design-HD-360-2048x1024.png" class="attachment-2048x2048 size-2048x2048 wp-image-34234" alt="Vue 360° Grand Canyon réaliste en réalité virtuelle, lumière naturelle filtrée, Présent Composé design pour SPLATGATE ⟶⦗⦘" srcset="https://presentcomposedesign.fr/wp-content/uploads/2025/11/GRAND-CANYON-Present-Compose-design-HD-360-2048x1024.png 2048w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/GRAND-CANYON-Present-Compose-design-HD-360-300x150.png 300w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/GRAND-CANYON-Present-Compose-design-HD-360-1920x960.png 1920w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/GRAND-CANYON-Present-Compose-design-HD-360-768x384.png 768w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/GRAND-CANYON-Present-Compose-design-HD-360-1536x768.png 1536w" sizes="(max-width: 2048px) 100vw, 2048px" />															</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-b6639fe elementor-section-full_width elementor-section-height-min-height elementor-section-items-bottom elementor-section-content-middle elementor-section-stretched elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no elementor-invisible" data-id="b6639fe" data-element_type="section" data-e-type="section" data-settings="{&quot;stretch_section&quot;:&quot;section-stretched&quot;,&quot;background_background&quot;:&quot;classic&quot;,&quot;animation&quot;:&quot;fadeInUp&quot;}">
						<div class="elementor-container elementor-column-gap-extended">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c5a8616" data-id="c5a8616" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<section class="elementor-section elementor-inner-section elementor-element elementor-element-adee29b elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="adee29b" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-ac60838" data-id="ac60838" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-343ca59 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="343ca59" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h1><span style="color: #0010ef;">Une aventure collaborative</span><span style="color: #0010ef; font-size: 16px;"> </span></h1><div class="vce-row-container" data-vce-boxed-width="true"><div id="el-ba3f564d" class="vce-row vce-row--col-gap-30 vce-row-equal-height vce-row-content--top" data-vce-do-apply="all el-ba3f564d"><div class="vce-row-content" data-vce-element-content="true"><div id="el-11f4390c" class="vce-col vce-col--md-auto vce-col--xs-1 vce-col--xs-last vce-col--xs-first vce-col--sm-last vce-col--sm-first vce-col--md-last vce-col--lg-last vce-col--xl-last vce-col--md-first vce-col--lg-first vce-col--xl-first"><div class="vce-col-inner" data-vce-do-apply="border margin background el-11f4390c"><div class="vce-col-content" data-vce-element-content="true" data-vce-do-apply="padding el-11f4390c"><div class="vce-google-fonts-heading vce-google-fonts-heading--align-left vce-google-fonts-heading--color-b-0-16-255--45--5C00FF--FF7200 vce-google-fonts-heading--font-family-Roboto"><div id="el-6e30c05c" class="vce-google-fonts-heading-wrapper"><div><span style="color: #0010ef;"> </span></div><div><p><span style="color: #0010ef;">SPLATGATE ⟶⦗⦘ est une expérience participative &amp; évolutive.</span></p></div><h2><span style="color: #000000;">Dans le hall, <b>un écran interactif vous permet de voter pour les prochains lieux que vous aimeriez visiter. </b><br />Vos suggestions et vos retours guident le choix des futures scènes à recréer.</span></h2><p>Le projet est entièrement autofinancé. Si cette démarche vous plaît et que vous souhaitez soutenir le développement de nouvelles destinations et l’amélioration de l’expérience, vous pouvez contribuer de plusieurs façons:<br /><br data-start="350" data-end="353" /><b>Faites un don</b> ponctuel ou récurrent : <b>en un clic, offrez un « café »</b> via la plateforme Buy Me a Coffe intégrée à cette page.<br />Les dons servent à financer la modélisation 3D, l’hébergement des expériences.</p><p><b>Partagez </b><span style="color: #0010ef; font-family: 'Inter Tight', sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: bold;">SPLATGATE ⟶⦗⦘ </span> : parlez‑en autour de vous, sur les réseaux sociaux ou dans votre blog. Plus la communauté est grande, plus les votes et les idées seront riches.</p></div></div><div class="vce-text-block"> </div></div></div></div></div></div></div><div class="vce-row-container" data-vce-boxed-width="true"><div id="el-d9d9a9fd" class="vce-row vce-row--col-gap-30 vce-row-equal-height vce-row-content--top" data-vce-do-apply="all el-d9d9a9fd"><div class="vce-row-content" data-vce-element-content="true"><div id="el-87440d41" class="vce-col vce-col--md-auto vce-col--xs-1 vce-col--xs-last vce-col--xs-first vce-col--sm-last vce-col--sm-first vce-col--md-last vce-col--lg-last vce-col--xl-last vce-col--md-first vce-col--lg-first vce-col--xl-first"><div class="vce-col-inner" data-vce-do-apply="border margin background el-87440d41"><div class="vce-col-content" data-vce-element-content="true" data-vce-do-apply="padding el-87440d41"><p><!-- /wp:vcwb/empty-comment-element-wrapper --></p></div></div></div><p><!-- /vcwb/dynamicElementComment:87440d41 --></p></div></div></div><p><!-- /vcwb/dynamicElementComment:d9d9a9fd --><!--vcv no format--></p>								</div>
				</div>
					</div>
		</div>
				<div class="elementor-column elementor-col-50 elementor-inner-column elementor-element elementor-element-7bf6dea" data-id="7bf6dea" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-859c5d0 elementor-widget elementor-widget-image" data-id="859c5d0" data-element_type="widget" data-e-type="widget" data-widget_type="image.default">
				<div class="elementor-widget-container">
															<img loading="lazy" decoding="async" width="1000" height="1000" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square4.jpg" class="attachment-full size-full wp-image-35360" alt="Visuel promotionnel de l&#039;expérience virtuelle SplatGate, un environnement immersif accessible via la plateforme Arrival.Space. Cette expérience permet aux utilisateurs de découvrir des paysages virtuels et des escapades gratuitement et sans limites. L&#039;image montre deux &quot;voyageurs&quot; en réalité virtuelle, explorant l&#039;univers SplatGate et les destinations proposées." srcset="https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square4.jpg 1000w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square4-300x300.jpg 300w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square4-150x150.jpg 150w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square4-768x768.jpg 768w, https://presentcomposedesign.fr/wp-content/uploads/2025/11/SplatGate_Present-Compose-design-UHD2025_square4-600x600.jpg 600w" sizes="(max-width: 1000px) 100vw, 1000px" />															</div>
				</div>
				<div class="elementor-element elementor-element-d211448 elementor-widget elementor-widget-spacer" data-id="d211448" data-element_type="widget" data-e-type="widget" data-widget_type="spacer.default">
				<div class="elementor-widget-container">
							<div class="elementor-spacer">
			<div class="elementor-spacer-inner"></div>
		</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-ea9b63d elementor-widget elementor-widget-html" data-id="ea9b63d" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<section class="pcd-hero-title-wrap">
    <div class="pcd-card" style="max-width: 600px; margin: 0 auto; text-align: center;">
        <h3 class="pcd-animate-text" style="font-size: 1.5rem !important; margin-bottom: 15px;">
            Soutenez SPLATGATE ⟶⦗⦘
        </h3>
        <p style="color: #1001ef; margin-bottom: 25px;">
            Ce hub est gratuit et sans publicité. 
            Votre contribution aide à financer les futures destinations et soutient l'innovation de manière générale</strong>.
        </p>
        <div class="pcd-btn">
            <a href="https://www.buymeacoffee.com/presentcomposedesign" target="_blank">
                ☕ Soutenir le projet
            </a>
        </div>
    </div>
</section>				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/splatgate/">SPLATGATE⟶⦗⦘</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		<enclosure url="https://presentcomposedesign.fr/wp-content/uploads/2025/11/video_presentation_SPLATGATE_PresentComposedesign-2025.mp4" length="45880030" type="video/mp4" />

			</item>
		<item>
		<title>Logo Toulouse Olympique</title>
		<link>https://presentcomposedesign.fr/logo-toulouse-olympique/</link>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 05 Nov 2025 08:52:34 +0000</pubDate>
				<category><![CDATA[Design graphique]]></category>
		<guid isPermaLink="false">https://presentcomposedesign.fr/?p=34053</guid>

					<description><![CDATA[<p>Le Toulouse Olympique XIII dévoile sa nouvelle identité visuelle. Présent Composé Design signe la refonte du logo du club, un symbole moderne, fort et emblématique du rugby à XIII.</p>
<p>Cet article <a href="https://presentcomposedesign.fr/logo-toulouse-olympique/">Logo Toulouse Olympique</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></description>
										<content:encoded><![CDATA[		<div data-elementor-type="wp-post" data-elementor-id="34053" class="elementor elementor-34053">
				<div class="wpr-jarallax elementor-element elementor-element-059db46 wpr-jarallax-yes e-con-full e-flex wpr-particle-no wpr-sticky-section-no e-con e-parent" speed-data="1.4" bg-image="https://presentcomposedesign.fr/wp-content/uploads/2025/11/20251005-SH_USP_YORK_KNIGHTS_TOULOUSE_5_Oct_254489-1536x1058-headerblue.png" scroll-effect="scroll" data-id="059db46" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;video&quot;}">
				<div class="elementor-element elementor-element-3b9fb77 elementor-widget__width-inherit elementor-widget-mobile__width-initial elementor-widget elementor-widget-html" data-id="3b9fb77" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<div id="container">
  <canvas id="canvas3d"></canvas>
</div>

<style>
  body {
    background-color: transparent;
    margin: 0;
    overflow: hidden;
    z-index: 99999999;
       
  }

  #container {
    width: 100%;
    height: 100vh; /* Fallback */
    height: 100dvh; /* Important pour mobile */
    display: flex;
    justify-content: center;
    z-index: 99999999;
    
    /* --- RÉGLAGE MOBILE (Par défaut) --- */
    /* On centre pour être sûr que l'objet soit au milieu du petit écran */
    align-items: center; 
    z-index: 99999999;
 
  }

  #canvas3d {
    width: 100%;
    height: 100%;
    outline: none;
    touch-action: scroll; 
    
  }

  /* --- RÉGLAGE DESKTOP (Écrans > 768px) --- */
  @media (min-width: 768px) {
    #container {
      /* On remet le réglage qui marchait "impeccable" pour toi avant */
      align-items: flex-start !important; 
    }
  }
</style>

<script type="module">
  import { Application } from "https://esm.sh/@splinetool/runtime";

  // --- CONFIGURATION DES URLS ---
  // 1. URL Desktop (Celle qui marche bien en large)
  const urlDesktop = "https://prod.spline.design/g5EDRtGbq4AqVzwE/scene.splinecode";
  
  // 2. URL Mobile (Celle que tu vas adapter/dézoomer)
  // (En attendant ton export, j'ai mis la même, mais penses à la changer ici)
  const urlMobile = "https://prod.spline.design/4dWPeXq4OX0rw49J/scene.splinecode"; 
  // ------------------------------

  const canvas = document.getElementById('canvas3d');
  const app = new Application(canvas);

  // Détection : Est-ce un mobile ?
  const isMobile = window.innerWidth < 768;

  // Choix de la scène
  const sceneToLoad = isMobile ? urlMobile : urlDesktop;

  app.load(sceneToLoad).then(() => {
      // Récupération des paramètres d'URL (Ton code original conservé)
      const urlParams = new URLSearchParams(window.location.search);
      const colorValue = urlParams.size > 1 ? urlParams.get('destinationValue') : 3.2;
      // app.setVariable('NomVariable', colorValue); // Si besoin
  });
</script>				</div>
				</div>
				</div>
				<section class="elementor-section elementor-top-section elementor-element elementor-element-2165a2a elementor-section-full_width elementor-section-height-min-height elementor-section-items-bottom elementor-section-content-middle elementor-section-stretched elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="2165a2a" data-element_type="section" data-e-type="section" data-settings="{&quot;stretch_section&quot;:&quot;section-stretched&quot;,&quot;background_background&quot;:&quot;classic&quot;}">
						<div class="elementor-container elementor-column-gap-extended">
					<div class="elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a50a530" data-id="a50a530" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<section class="elementor-section elementor-inner-section elementor-element elementor-element-c0f6a58 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no" data-id="c0f6a58" data-element_type="section" data-e-type="section">
						<div class="elementor-container elementor-column-gap-default">
					<div class="elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-fe979b3" data-id="fe979b3" data-element_type="column" data-e-type="column">
			<div class="elementor-widget-wrap elementor-element-populated">
						<div class="elementor-element elementor-element-3984c60 elementor-widget elementor-widget-heading" data-id="3984c60" data-element_type="widget" data-e-type="widget" data-widget_type="heading.default">
				<div class="elementor-widget-container">
					<h1 class="elementor-heading-title elementor-size-default">Toulouse Olympique 13</h1>				</div>
				</div>
					</div>
		</div>
					</div>
		</section>
					</div>
		</div>
					</div>
		</section>
		<div class="elementor-element elementor-element-d9224c2 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="d9224c2" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;classic&quot;}">
					<div class="e-con-inner">
		<div class="elementor-element elementor-element-af1f964 e-con-full e-flex wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-child" data-id="af1f964" data-element_type="container" data-e-type="container">
				<div class="elementor-element elementor-element-edc9229 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="edc9229" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<h1><span style="color: #0a0a3c;">Refonte graphique</span></h1><div data-vce-boxed-width="true"><div data-vce-do-apply="all el-ba3f564d"><div data-vce-element-content="true"><div data-vce-do-apply="border margin background el-11f4390c"><div data-vce-element-content="true" data-vce-do-apply="padding el-11f4390c"><div><span style="color: #0010ef;"> </span></div><h6>Accompagnement du club de Rugby à 13 du Toulouse Olympique dans la transition vers une nouvelle identité suite à son passage en superleague. </h6><div><strong style="color: #333333; font-family: 'Inter Tight', sans-serif; font-size: 20px;"><br /><span style="color: #0a0a3c;">🡺 Refonte intégrale du logo du club et de ses déclinaisons</span></strong></div><div><strong style="color: #333333; font-family: 'Inter Tight', sans-serif; font-size: 20px;"><br /><span style="color: #0a0a3c;">🡺 Réalisation de la brochure de présentation du club</span><br /></strong></div><div><strong style="color: #333333; font-family: 'Inter Tight', sans-serif; font-size: 20px;"> </strong></div></div></div></div></div></div><div data-vce-boxed-width="true"><div data-vce-do-apply="all el-d9d9a9fd"><div data-vce-element-content="true"><div><div data-vce-do-apply="border margin background el-87440d41"><div data-vce-element-content="true" data-vce-do-apply="padding el-87440d41"><p><!-- /wp:vcwb/empty-comment-element-wrapper --></p></div></div></div><p><!-- /vcwb/dynamicElementComment:87440d41 --></p></div></div></div><p><!-- /vcwb/dynamicElementComment:d9d9a9fd --><!--vcv no format--></p>								</div>
				</div>
				<div class="elementor-element elementor-element-2cbdac1 elementor-widget elementor-widget-wpr-flip-carousel" data-id="2cbdac1" data-element_type="widget" data-e-type="widget" data-widget_type="wpr-flip-carousel.default">
				<div class="elementor-widget-container">
					<div class="wpr-flip-carousel-wrapper"><div class="wpr-flip-carousel" data-settings="{&quot;starts_from_center&quot;:&quot;yes&quot;,&quot;carousel_type&quot;:&quot;carousel&quot;,&quot;loop&quot;:&quot;yes&quot;,&quot;autoplay&quot;:false,&quot;autoplay_milliseconds&quot;:0,&quot;pause_on_hover&quot;:false,&quot;play_on_click&quot;:&quot;yes&quot;,&quot;play_on_scroll&quot;:&quot;yes&quot;,&quot;pagination_position&quot;:null,&quot;spacing&quot;:-0.6,&quot;button_prev&quot;:&quot;&quot;,&quot;button_next&quot;:&quot;&quot;,&quot;pagination_bg_color_hover&quot;:null}"><ul class="wpr-flip-items-wrapper"><li class="wpr-flip-item" data-flip-title=""><figure><a ><img decoding="async" alt="Déclinaison-logo-TO13-Alban-DESBARAX-2025" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/LOGO_TO_blason_blanc-fond-bleu-300x300.jpg" /></a></figure></li><li class="wpr-flip-item" data-flip-title=""><figure><a ><img decoding="async" alt="Déclinaison-logo-TO13-Alban-DESBARAX-2025" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/LOGO_TO_blason_blanc-fond-transp-surbleu-300x300.jpg" /></a></figure></li><li class="wpr-flip-item" data-flip-title=""><figure><a ><img decoding="async" alt="Déclinaison-logo-TO13-Alban-DESBARAX-2025" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/LOGO_TO_blason_bleu-fond-blanc-300x300.jpg" /></a></figure></li><li class="wpr-flip-item" data-flip-title=""><figure><a ><img decoding="async" alt="Déclinaison-logo-TO13-Alban-DESBARAX-2025" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/LOGO_TO_blason_transp-fond-blanc-surbleu-300x300.jpg" /></a></figure></li></ul></div></div>				</div>
				</div>
				</div>
		<div class="elementor-element elementor-element-465691b e-con-full e-flex wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-child" data-id="465691b" data-element_type="container" data-e-type="container">
				<div class="elementor-element elementor-element-801e751 elementor-widget elementor-widget-video" data-id="801e751" data-element_type="widget" data-e-type="widget" data-settings="{&quot;video_type&quot;:&quot;hosted&quot;,&quot;autoplay&quot;:&quot;yes&quot;,&quot;play_on_mobile&quot;:&quot;yes&quot;,&quot;mute&quot;:&quot;yes&quot;,&quot;loop&quot;:&quot;yes&quot;}" data-widget_type="video.default">
				<div class="elementor-widget-container">
							<div class="e-hosted-video elementor-wrapper elementor-open-inline">
					<video class="elementor-video" src="https://presentcomposedesign.fr/wp-content/uploads/2025/11/Presentation-recherches-logo-Toulouse-Olympique_Present-Compose-design-nov2025-1.mp4" autoplay="" loop="" muted="muted" playsinline="" controlsList="nodownload" poster="https://presentcomposedesign.fr/wp-content/uploads/2025/11/Presentation-recherches-logo-Toulouse-Olympique-v3.jpg"></video>
				</div>
						</div>
				</div>
				<div class="elementor-element elementor-element-8fd00b3 elementor-widget__width-initial elementor-widget elementor-widget-text-editor" data-id="8fd00b3" data-element_type="widget" data-e-type="widget" data-widget_type="text-editor.default">
				<div class="elementor-widget-container">
									<div data-vce-boxed-width="true"><div data-vce-do-apply="all el-ba3f564d"><div data-vce-element-content="true"><div data-vce-do-apply="border margin background el-11f4390c"><div data-vce-element-content="true" data-vce-do-apply="padding el-11f4390c"><div> </div><h2><span style="color: #0010ef;"><strong>⦿ Ecoute attentive des besoins du club<br /></strong></span><strong style="font-family: 'Inter Tight', sans-serif; font-size: 20px;"><span style="color: #0010ef;"><br /></span></strong></h2><h2><strong style="font-family: 'Inter Tight', sans-serif; font-size: 20px;"><span style="color: #0010ef;">⦿</span></strong> <span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400; color: #0010ef;"><strong>Conception</strong></span><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400;">, réalisation et proposition d&rsquo;un </span><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400; color: #0010ef;"><strong> « cahier de recherches ».<br /></strong></span><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400; color: #0010ef;"><strong><br /></strong></span></h2><h2><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400; color: #0010ef;"><strong>⦿</strong></span> <strong style="font-family: 'Inter Tight', sans-serif; font-size: 20px;"><span style="color: #0010ef;">Discussions &amp; modifications</span></strong><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400;">, entretiens avec les membres du Club, échanges constructifs, prise en compte des remarques.<br /></span><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400; color: #0010ef;"><strong><br /></strong></span></h2><h2><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400; color: #0010ef;"><strong>⦿ Production et fourniture des livrables</strong></span><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400;">, conception &amp; réalisation des dessins vectoriels, réalisations des différentes versions et déclinaisons en fonctions des cas d&rsquo;usage.<br /></span><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400; color: #0010ef;"><br /></span></h2><h2><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400; color: #0010ef;">⦿</span> <strong style="font-family: 'Inter Tight', sans-serif; font-size: 20px;"><span style="color: #0010ef;">Gestion et suivi</span></strong><span style="font-family: 'Inter Tight', sans-serif; font-size: 20px; font-weight: 400;">, Interlocuteur unique pour tout le déroulé du projet </span></h2><h2 style="text-align: center;"><span style="color: #0010ef;"><strong><i class="fa-solid fa-chevron-down"></i> </strong></span></h2><h2 style="text-align: center;"><span style="color: #0010ef;"><b>Vous souhaitez faire appel à mes services ?</b></span></h2></div></div></div></div></div><div data-vce-boxed-width="true"><div data-vce-do-apply="all el-d9d9a9fd"><div data-vce-element-content="true"><div><div data-vce-do-apply="border margin background el-87440d41"><div data-vce-element-content="true" data-vce-do-apply="padding el-87440d41"><p><!-- /wp:vcwb/empty-comment-element-wrapper --></p></div></div></div><p><!-- /vcwb/dynamicElementComment:87440d41 --></p></div></div></div><p><!-- /vcwb/dynamicElementComment:d9d9a9fd --><!--vcv no format--></p>								</div>
				</div>
				<div class="elementor-element elementor-element-47d2284 elementor-align-center elementor-widget__width-initial pcd-btn-primary pcd-holo elementor-widget elementor-widget-button" data-id="47d2284" data-element_type="widget" data-e-type="widget" data-widget_type="button.default">
				<div class="elementor-widget-container">
									<div class="elementor-button-wrapper">
					<a class="elementor-button elementor-button-link elementor-size-sm" href="https://presentcomposedesign.fr/contact/">
						<span class="elementor-button-content-wrapper">
									<span class="elementor-button-text">Demander un rendez-vous</span>
					</span>
					</a>
				</div>
								</div>
				</div>
				</div>
					</div>
				</div>
		<div class="elementor-element elementor-element-446f0f1 e-flex e-con-boxed wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-parent" data-id="446f0f1" data-element_type="container" data-e-type="container" data-settings="{&quot;background_background&quot;:&quot;classic&quot;}">
					<div class="e-con-inner">
		<div class="elementor-element elementor-element-64e8473 e-con-full e-flex wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-child" data-id="64e8473" data-element_type="container" data-e-type="container">
				<div class="elementor-element elementor-element-41dacf7 elementor-widget elementor-widget-html" data-id="41dacf7" data-element_type="widget" data-e-type="widget" data-widget_type="html.default">
				<div class="elementor-widget-container">
					<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="https://www.instagram.com/reel/DQd_MU3DIIv/?utm_source=ig_embed&amp;utm_campaign=loading" data-instgrm-version="14" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:540px; min-width:326px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:16px;"> <a href="https://www.instagram.com/reel/DQd_MU3DIIv/?utm_source=ig_embed&amp;utm_campaign=loading" style=" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;" target="_blank"> <div style=" display: flex; flex-direction: row; align-items: center;"> <div style="background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 40px; margin-right: 14px; width: 40px;"></div> <div style="display: flex; flex-direction: column; flex-grow: 1; justify-content: center;"> <div style=" background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; margin-bottom: 6px; width: 100px;"></div> <div style=" background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; width: 60px;"></div></div></div><div style="padding: 19% 0;"></div> <div style="display:block; height:50px; margin:0 auto 12px; width:50px;"><svg width="50px" height="50px" viewBox="0 0 60 60" version="1.1" xmlns="https://www.w3.org/2000/svg" xmlns:xlink="https://www.w3.org/1999/xlink"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g transform="translate(-511.000000, -20.000000)" fill="#000000"><g><path d="M556.869,30.41 C554.814,30.41 553.148,32.076 553.148,34.131 C553.148,36.186 554.814,37.852 556.869,37.852 C558.924,37.852 560.59,36.186 560.59,34.131 C560.59,32.076 558.924,30.41 556.869,30.41 M541,60.657 C535.114,60.657 530.342,55.887 530.342,50 C530.342,44.114 535.114,39.342 541,39.342 C546.887,39.342 551.658,44.114 551.658,50 C551.658,55.887 546.887,60.657 541,60.657 M541,33.886 C532.1,33.886 524.886,41.1 524.886,50 C524.886,58.899 532.1,66.113 541,66.113 C549.9,66.113 557.115,58.899 557.115,50 C557.115,41.1 549.9,33.886 541,33.886 M565.378,62.101 C565.244,65.022 564.756,66.606 564.346,67.663 C563.803,69.06 563.154,70.057 562.106,71.106 C561.058,72.155 560.06,72.803 558.662,73.347 C557.607,73.757 556.021,74.244 553.102,74.378 C549.944,74.521 548.997,74.552 541,74.552 C533.003,74.552 532.056,74.521 528.898,74.378 C525.979,74.244 524.393,73.757 523.338,73.347 C521.94,72.803 520.942,72.155 519.894,71.106 C518.846,70.057 518.197,69.06 517.654,67.663 C517.244,66.606 516.755,65.022 516.623,62.101 C516.479,58.943 516.448,57.996 516.448,50 C516.448,42.003 516.479,41.056 516.623,37.899 C516.755,34.978 517.244,33.391 517.654,32.338 C518.197,30.938 518.846,29.942 519.894,28.894 C520.942,27.846 521.94,27.196 523.338,26.654 C524.393,26.244 525.979,25.756 528.898,25.623 C532.057,25.479 533.004,25.448 541,25.448 C548.997,25.448 549.943,25.479 553.102,25.623 C556.021,25.756 557.607,26.244 558.662,26.654 C560.06,27.196 561.058,27.846 562.106,28.894 C563.154,29.942 563.803,30.938 564.346,32.338 C564.756,33.391 565.244,34.978 565.378,37.899 C565.522,41.056 565.552,42.003 565.552,50 C565.552,57.996 565.522,58.943 565.378,62.101 M570.82,37.631 C570.674,34.438 570.167,32.258 569.425,30.349 C568.659,28.377 567.633,26.702 565.965,25.035 C564.297,23.368 562.623,22.342 560.652,21.575 C558.743,20.834 556.562,20.326 553.369,20.18 C550.169,20.033 549.148,20 541,20 C532.853,20 531.831,20.033 528.631,20.18 C525.438,20.326 523.257,20.834 521.349,21.575 C519.376,22.342 517.703,23.368 516.035,25.035 C514.368,26.702 513.342,28.377 512.574,30.349 C511.834,32.258 511.326,34.438 511.181,37.631 C511.035,40.831 511,41.851 511,50 C511,58.147 511.035,59.17 511.181,62.369 C511.326,65.562 511.834,67.743 512.574,69.651 C513.342,71.625 514.368,73.296 516.035,74.965 C517.703,76.634 519.376,77.658 521.349,78.425 C523.257,79.167 525.438,79.673 528.631,79.82 C531.831,79.965 532.853,80.001 541,80.001 C549.148,80.001 550.169,79.965 553.369,79.82 C556.562,79.673 558.743,79.167 560.652,78.425 C562.623,77.658 564.297,76.634 565.965,74.965 C567.633,73.296 568.659,71.625 569.425,69.651 C570.167,67.743 570.674,65.562 570.82,62.369 C570.966,59.17 571,58.147 571,50 C571,41.851 570.966,40.831 570.82,37.631"></path></g></g></g></svg></div><div style="padding-top: 8px;"> <div style=" color:#3897f0; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:550; line-height:18px;">Voir cette publication sur Instagram</div></div><div style="padding: 12.5% 0;"></div> <div style="display: flex; flex-direction: row; margin-bottom: 14px; align-items: center;"><div> <div style="background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(0px) translateY(7px);"></div> <div style="background-color: #F4F4F4; height: 12.5px; transform: rotate(-45deg) translateX(3px) translateY(1px); width: 12.5px; flex-grow: 0; margin-right: 14px; margin-left: 2px;"></div> <div style="background-color: #F4F4F4; border-radius: 50%; height: 12.5px; width: 12.5px; transform: translateX(9px) translateY(-18px);"></div></div><div style="margin-left: 8px;"> <div style=" background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 20px; width: 20px;"></div> <div style=" width: 0; height: 0; border-top: 2px solid transparent; border-left: 6px solid #f4f4f4; border-bottom: 2px solid transparent; transform: translateX(16px) translateY(-4px) rotate(30deg)"></div></div><div style="margin-left: auto;"> <div style=" width: 0px; border-top: 8px solid #F4F4F4; border-right: 8px solid transparent; transform: translateY(16px);"></div> <div style=" background-color: #F4F4F4; flex-grow: 0; height: 12px; width: 16px; transform: translateY(-4px);"></div> <div style=" width: 0; height: 0; border-top: 8px solid #F4F4F4; border-left: 8px solid transparent; transform: translateY(-4px) translateX(8px);"></div></div></div> <div style="display: flex; flex-direction: column; flex-grow: 1; justify-content: center; margin-bottom: 24px;"> <div style=" background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; margin-bottom: 6px; width: 224px;"></div> <div style=" background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; width: 144px;"></div></div></a><p style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; line-height:17px; margin-bottom:0; margin-top:8px; overflow:hidden; padding:8px 0 7px; text-align:center; text-overflow:ellipsis; white-space:nowrap;"><a href="https://www.instagram.com/reel/DQd_MU3DIIv/?utm_source=ig_embed&amp;utm_campaign=loading" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px; text-decoration:none;" target="_blank">Une publication partagée par 𝐓𝐎𝐔𝐋𝐎𝐔𝐒𝐄 𝐎𝐋𝐘𝐌𝐏𝐈𝐐𝐔𝐄 (@toulouseolympiquerugby)</a></p></div></blockquote>
<script async src="//www.instagram.com/embed.js"></script>				</div>
				</div>
				</div>
		<div class="elementor-element elementor-element-2c5231b e-con-full e-flex wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no e-con e-child" data-id="2c5231b" data-element_type="container" data-e-type="container">
				</div>
					</div>
				</div>
				</div>
		<p>Cet article <a href="https://presentcomposedesign.fr/logo-toulouse-olympique/">Logo Toulouse Olympique</a> est apparu en premier sur <a href="https://presentcomposedesign.fr">Présent Composé design</a>.</p>
]]></content:encoded>
					
		
		<enclosure url="https://presentcomposedesign.fr/wp-content/uploads/2025/11/Presentation-recherches-logo-Toulouse-Olympique_Present-Compose-design-nov2025-1.mp4" length="19567285" type="video/mp4" />

			</item>
	</channel>
</rss>
