1(() => { 2 const SCROLLBAR_GRAB_ZONE = 24; // px depuis le bord droit 3 let scrollbarGrabbed = false; 4 5 function isOnScrollbar(e) { 6 return e.clientX >= window.innerWidth - SCROLLBAR_GRAB_ZONE; 7 } 8 9 window.addEventListener("mousedown", (e) => { 10 if (isOnScrollbar(e)) { 11 scrollbarGrabbed = true; 12 window.__AntesySmoothScroll?.disable(); 13 } 14 }, true); 15 16 window.addEventListener("mouseup", () => { 17 if (scrollbarGrabbed) { 18 scrollbarGrabbed = false; 19 // ?? on ne réactive PAS immédiatement 20 requestAnimationFrame(() => { 21 window.__AntesySmoothScroll?.enable(); 22 }); 23 } 24 }, true); 25 // =========================== 26 // SMOOTH SCROLL (desktop) 27 // =========================== 28 const IS_COARSE = window.matchMedia?.("(pointer: coarse)")?.matches ?? false; 29 const SCROLLER = document.scrollingElement || document.documentElement; 30 31 // Smooth-scroll custom UNIQUEMENT sur la home (seule page 3D désormais). 32 // Ailleurs : scroll natif ? évite le "scroll tout seul". 33 const _p = (location.pathname || "/").replace(/\/+$/, "").toLowerCase(); 34 const IS_HOME = _p === "" || _p === "/home" || _p === "/en" || _p === "/en/home"; 35 36 // Desktop only: if coarse pointer, do nothing. 37 if (IS_COARSE) { 38 window.__AntesySmoothScroll = { enable() { }, disable() { }, isEnabled: () => false }; 39 return; 40 } 41 42 // Tunables 43 const START_SLOW_FACTOR = 0.38; 44 const EASE = 0.45; 45 const KEY_STEP = 60; 46 47 let active = false; 48 let factor = START_SLOW_FACTOR; 49 50 let target = SCROLLER.scrollTop || 0; 51 let current = target; 52 let rafId = null; 53 54 const clamp = (v, min, max) => Math.min(max, Math.max(min, v)); 55 const maxScroll = () => (SCROLLER.scrollHeight - window.innerHeight); 56 57 const loop = () => { 58 // If disabled mid-loop, stop cleanly 59 if (!active) return; 60 61 current += (target - current) * EASE; 62 63 if (Math.abs(target - current) < 0.3) current = target; 64 65 // IMPORTANT: use scrollTo but keep current bounded 66 current = clamp(current, 0, maxScroll()); 67 window.scrollTo(0, current); 68 69 rafId = requestAnimationFrame(loop); 70 }; 71 72 const onWheel = (e) => { 73 // Compute first, preventDefault ONLY if we will handle it. 74 const delta = e.deltaY || e.wheelDelta || 0; 75 76 const atTop = (current <= 0.5) && (delta < 0); 77 const atBottom = (current >= maxScroll() - 0.5) && (delta > 0); 78 79 // If pushing against bounds, let the browser handle it (no preventDefault) 80 if (atTop || atBottom) { 81 // Keep internal state coherent 82 target = clamp(target, 0, maxScroll()); 83 current = clamp(current, 0, maxScroll()); 84 return; 85 } 86 87 e.preventDefault(); 88 target = clamp(target + delta * factor, 0, maxScroll()); 89 }; 90 91 const onKeyDown = (e) => { 92 if (e.key === "ArrowDown") { 93 e.preventDefault(); 94 target = clamp(target + KEY_STEP * factor, 0, maxScroll()); 95 } else if (e.key === "ArrowUp") { 96 e.preventDefault(); 97 target = clamp(target - KEY_STEP * factor, 0, maxScroll()); 98 } 99 }; 100 101 function enableSmooth() { 102 if (active) return; 103 active = true; 104 105 // Align internal values to real scroll position 106 const s = SCROLLER.scrollTop || 0; 107 current = target = clamp(s, 0, maxScroll()); 108 109 window.addEventListener("wheel", onWheel, { passive: false }); 110 window.addEventListener("keydown", onKeyDown, { passive: false }); 111 112 rafId = requestAnimationFrame(loop); 113 } 114 115 function disableSmooth() { 116 if (!active) return; 117 active = false; 118 119 window.removeEventListener("wheel", onWheel); 120 window.removeEventListener("keydown", onKeyDown); 121 122 if (rafId) cancelAnimationFrame(rafId); 123 rafId = null; 124 125 // Snap to a stable position (avoid fractional jitter) 126 current = clamp(current, 0, maxScroll()); 127 window.scrollTo(0, Math.round(current)); 128 target = current; 129 } 130 131 window.__AntesySmoothScroll = { 132 enable: enableSmooth, 133 disable: disableSmooth, 134 isEnabled: () => active, 135 // Programmatic scroll : met à jour target directement pour éviter l'écrasement du loop 136 scrollTo: (y) => { 137 target = clamp(y, 0, maxScroll()); 138 current = target; // snap immédiat, pas d'animation 139 if (!active) window.scrollTo(0, Math.round(target)); 140 else window.scrollTo(0, Math.round(target)); 141 } 142 }; 143 144 // Démarre activé UNIQUEMENT sur la home (sinon scroll natif). 145 if (IS_HOME) enableSmooth(); 146})(); 147 148// ===================================== 149// SCROLL HANDLER (canvas lock/unlock) 150// ===================================== 151let canvasFixed = false; 152window.cameraLocked2 = false; 153 154// HYSTERESIS: avoid ON/OFF around same pixel 155const LOCK_SCROLL_Y = 260; // lock when going down past this 156const UNLOCK_SCROLL_Y = 180; // unlock only when going back up above this (lower) 157 158// UI show/hide (hero) 159const HIDE_UI_AFTER_Y = 20; 160const SHOW_UI_BEFORE_Y = 50; // hysteresis 161 162// Avoid toggling smooth scroll inside the scroll event synchronously 163let pendingSmoothToggle = null; 164function requestSmooth(enabled) { 165 // if on mobile / not defined, ignore 166 const api = window.__AntesySmoothScroll; 167 if (!api) return; 168 169 // cancel previous request in same frame 170 if (pendingSmoothToggle) cancelAnimationFrame(pendingSmoothToggle); 171 172 pendingSmoothToggle = requestAnimationFrame(() => { 173 pendingSmoothToggle = null; 174 if (enabled) api.enable(); 175 else api.disable(); 176 });
177} 178 179let ticking = false; 180 181window.addEventListener( 182 "scroll", 183 () => { 184 if (ticking) return; 185 ticking = true; 186 187 requestAnimationFrame(() => { 188 ticking = false; 189 190 try { 191 // Dock + console "Parlez-nous de votre projet" : retirés dès qu'on scrolle. 192 // Classe sur <body> (immune aux re-renders Blazor de #antesyDock). 193 const _sY = window.scrollY || document.documentElement.scrollTop || 0; 194 document.body.classList.toggle('is-scrolled', _sY > 20); 195 196 // Pendant le jeu, aucune transition de scroll (canvas-fixed, Animate, hide UI) 197 if (document.body.classList.contains('game-active')) return; 198 199 const canvas = document.querySelector("#babylonCanvas"); 200 if (!canvas) return; 201 202 const titleContainer = document.querySelector(".TextAppears"); 203 const HeroTexte = document.querySelector(".hero-over-babylon"); 204 const dock = document.querySelector(".dock"); 205 const consoleWin = 206 document.getElementById("antesyConsole") || 207 document.querySelector(".console-window"); 208 209 const scrollY = 210 window.scrollY || document.documentElement.scrollTop || 0; 211 212 // ---- Lock canvas ---- 213 if (!canvasFixed && scrollY >= LOCK_SCROLL_Y) { 214 canvas.classList.add("canvas-fixed"); 215 if (titleContainer) titleContainer.classList.add("Animate"); 216 217 canvasFixed = true; 218 window.cameraLocked2 = true; 219 220 // IMPORTANT: defer to avoid input jank 221 requestAnimationFrame(() => requestSmooth(false)); 222 } 223 224 // ---- Unlock canvas ---- 225 if (canvasFixed && scrollY <= UNLOCK_SCROLL_Y) { 226 canvas.classList.remove("canvas-fixed"); 227 if (titleContainer) titleContainer.classList.remove("Animate"); 228 229 canvasFixed = false; 230 window.cameraLocked2 = false; 231 232 requestAnimationFrame(() => requestSmooth(true)); 233 } 234 235 // ---- UI hide/show with hysteresis ---- 236 if (!canvasFixed && scrollY >= HIDE_UI_AFTER_Y) { 237 if (dock && !dock.classList.contains("is-scroll-hidden")) { 238 dock.classList.add("is-scroll-hidden"); 239 } 240 if (consoleWin && !consoleWin.classList.contains("is-scroll-hidden")) { 241 consoleWin.classList.add("is-scroll-hidden"); 242 } 243 if (HeroTexte && !HeroTexte.classList.contains("IsInvisible")) { 244 HeroTexte.classList.add("IsInvisible"); 245 } 246 } 247 248 if (!canvasFixed && scrollY <= SHOW_UI_BEFORE_Y) { 249 if (dock && dock.classList.contains("is-scroll-hidden")) { 250 dock.classList.remove("is-scroll-hidden"); 251 } 252 if (consoleWin && consoleWin.classList.contains("is-scroll-hidden")) { 253 consoleWin.classList.remove("is-scroll-hidden"); 254 } 255 if (HeroTexte && HeroTexte.classList.contains("IsInvisible")) { 256 HeroTexte.classList.remove("IsInvisible"); 257 } 258 } 259 } catch (e) { 260 console.error("Erreur scroll handler:", e); 261 } 262 }); 263 }, 264 { passive: true } 265); 266 267// ===================================================== 268// MODE DE PAGE (appelé par MainLayout, CSP-safe : fonction nommée, pas d'eval) 269// light = page hero léger (barre blanche + --babylon-height:0) 270// is3d = page avec scène Babylon (smooth-scroll custom activé) 271// ===================================================== 272window.antesyPageMode = function (light, is3d) { 273 try { document.documentElement.classList.toggle('light-hero', !!light); } catch (e) { } 274 try { 275 if (window.__AntesySmoothScroll) { 276 if (is3d) window.__AntesySmoothScroll.enable(); 277 else window.__AntesySmoothScroll.disable(); 278 } 279 } catch (e) { } 280}; 281 282// Recalcule le mode depuis l'URL indépendant de l'interop Blazor (marche sur les 283// pages rendues en statique). Doit rester synchronisé avec MainLayout.IsLight. 284window.antesyApplyPageMode = function () { 285 try { 286 var p = (location.pathname || '/').replace(/\/+$/, '').toLowerCase(); 287 var home = p === '' || p === '/home' || p === '/en' || p === '/en/home'; 288 var imm = p.indexOf('/configurateur-voiture') >= 0 || p.indexOf('/car-configurator') >= 0; 289 var lab = p.indexOf('/lab') === 0; 290 var light = !home && !imm && !lab; 291 window.antesyPageMode(light, !light && !imm); 292 } catch (e) { } 293}; 294// Navigation "enhanced" (blazor.web.js) = pas de rechargement complet ? le script <head> 295// ne re-tourne pas. On ré-applique donc à chaque navigation enhanced. 296try { document.addEventListener('DOMContentLoaded', window.antesyApplyPageMode); } catch (e) { } 297try { if (window.Blazor && Blazor.addEventListener) Blazor.addEventListener('enhancedload', window.antesyApplyPageMode); } catch (e) { } 298try { window.addEventListener('blazor:enhancedload', window.antesyApplyPageMode); } catch (e) { } 299 300// Init de la bande de triangles (TriLineHero) SANS dépendre de l'interactivité Blazor. 301// Les pages light-hero sont souvent rendues en statique ? le OnAfterRender du composant 302// ne tourne pas ? l'effet de scatter au scroll n'était jamais câblé. On l'initialise ici, 303// au chargement et à chaque navigation enhanced (dispose si la page n'a pas de #tlHero). 304window.antesyInitTriLine = function () { 305 try { 306 var el = document.getElementById('tlHero'); 307 import('/js/triLineScroll.js?v=101').then(function (m) { 308 if (el) m.initTriLine('tlHero', { rangeFactor: 0.35, autoPlay: true, clickPreview: false }); 309 else if (m.disposeTriLine) m.disposeTriLine('tlHero'); 310 }).catch(function () { });
311 } catch (e) { } 312}; 313try { document.addEventListener('DOMContentLoaded', window.antesyInitTriLine); } catch (e) { } 314try { if (window.Blazor && Blazor.addEventListener) Blazor.addEventListener('enhancedload', window.antesyInitTriLine); } catch (e) { } 315try { window.addEventListener('blazor:enhancedload', window.antesyInitTriLine); } catch (e) { } 316 317// ----------------------------------------------------------------------------- 318// Scroll-to-top a CHAQUE navigation enhanced (blazor.web.js). 319// Sans ca, la position de scroll de la page precedente est conservee : un CTA situe 320// en bas de page (ex: GamePulse "Lancer votre projet avec nous", lien <a href>) ouvre 321// la page cible deja scrollee en bas. On ignore les liens vers une ancre (#section). 322// Enregistrement robuste : window.Blazor peut ne pas etre pret quand ce script (defer) 323// s'execute -> on reessaie jusqu'a ce que Blazor.addEventListener existe. 324// ----------------------------------------------------------------------------- 325window.antesyScrollTopOnNav = function () { 326 try { 327 if (location.hash && location.hash.length > 1) return; // lien #ancre : ne pas remonter 328 // Aligne aussi le smooth-scroll custom (home) pour eviter qu'il "restaure" la position. 329 if (window.__AntesySmoothScroll && window.__AntesySmoothScroll.scrollTo) { 330 try { window.__AntesySmoothScroll.scrollTo(0); } catch (e) { } 331 } 332 window.scrollTo(0, 0); 333 } catch (e) { } 334}; 335(function registerScrollTopOnNav() { 336 var tries = 0; 337 (function attach() { 338 if (window.Blazor && typeof window.Blazor.addEventListener === 'function') { 339 try { window.Blazor.addEventListener('enhancedload', window.antesyScrollTopOnNav); } catch (e) { } 340 } else if (tries++ < 100) { 341 setTimeout(attach, 50); 342 } 343 })(); 344})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.