|
4 | 4 | <meta charset="UTF-8"/> |
5 | 5 | <meta name="viewport" content="width=device-width,initial-scale=1.0"/> |
6 | 6 | <title>Synapse.js — Zero-DOM WebGPU Rendering</title> |
| 7 | + |
| 8 | + <!-- SEO --> |
| 9 | + <meta name="description" content="Synapse.js est un moteur de rendu Zero-DOM pour le web. Il transforme n'importe quel framework en cible WebGPU avec un scene graph en RAM et un pipeline GPU pur. 61x plus rapide que le DOM."/> |
| 10 | + <meta name="keywords" content="synapse, webgpu, zero-dom, rendering engine, gpu, javascript, typescript, scene graph, instancing, react, svelte, angular"/> |
| 11 | + <meta name="author" content="Klaynight"/> |
| 12 | + <meta name="robots" content="index, follow"/> |
| 13 | + <link rel="canonical" href="https://klaynight-dev.github.io/SynapseJS/"/> |
| 14 | + |
| 15 | + <!-- Open Graph --> |
| 16 | + <meta property="og:type" content="website"/> |
| 17 | + <meta property="og:title" content="Synapse.js — Zero-DOM WebGPU Rendering Engine"/> |
| 18 | + <meta property="og:description" content="Moteur de rendu Zero-DOM pour le web. Scene graph en RAM, pipeline GPU pur, 1 draw call pour des milliers d'elements. 61x plus rapide que le DOM."/> |
| 19 | + <meta property="og:url" content="https://klaynight-dev.github.io/SynapseJS/"/> |
| 20 | + <meta property="og:image" content="https://klaynight-dev.github.io/SynapseJS/assets/synapse-logo.svg"/> |
| 21 | + <meta property="og:site_name" content="Synapse.js"/> |
| 22 | + <meta property="og:locale" content="fr_FR"/> |
| 23 | + |
| 24 | + <!-- Twitter Card --> |
| 25 | + <meta name="twitter:card" content="summary_large_image"/> |
| 26 | + <meta name="twitter:title" content="Synapse.js — Zero-DOM WebGPU Rendering"/> |
| 27 | + <meta name="twitter:description" content="Moteur de rendu Zero-DOM WebGPU. 857 FPS pour 10k elements, 1 draw call, 61x plus rapide que le DOM."/> |
| 28 | + <meta name="twitter:image" content="https://klaynight-dev.github.io/SynapseJS/assets/synapse-logo.svg"/> |
| 29 | + |
| 30 | + <!-- Theme --> |
| 31 | + <meta name="theme-color" content="#f5f0e8"/> |
| 32 | + <meta name="color-scheme" content="light"/> |
| 33 | + |
| 34 | + <!-- Favicon --> |
| 35 | + <link rel="icon" type="image/svg+xml" href="/assets/synapse-logo.svg"/> |
| 36 | + |
7 | 37 | <link rel="preconnect" href="https://fonts.googleapis.com"/> |
8 | 38 | <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> |
9 | 39 | <link href="https://fonts.googleapis.com/css2?family=Caveat:wght@400;500;600;700&family=Patrick+Hand&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"/> |
@@ -277,132 +307,6 @@ <h2>Pret a <span class="strike">utiliser le DOM</span> passer au GPU ?</h2> |
277 | 307 | <div class="footer">© 2026 <a href="https://github.com/Klaynight-dev/SynapseJS" target="_blank">Synapse.js</a> — Zero-DOM WebGPU rendering core.</div> |
278 | 308 | </div> |
279 | 309 |
|
280 | | -<script> |
281 | | -// ═══════════════════════════════════════ |
282 | | -// 1. SCROLL PROGRESS BAR |
283 | | -// ═══════════════════════════════════════ |
284 | | -const progressBar=document.getElementById('scroll-progress'); |
285 | | -function updateProgress(){ |
286 | | - const h=document.documentElement.scrollHeight-window.innerHeight; |
287 | | - progressBar.style.width=(h>0?(window.scrollY/h)*100:0)+'%'; |
288 | | -} |
289 | | -window.addEventListener('scroll',updateProgress,{passive:true}); |
290 | | -updateProgress(); |
291 | | - |
292 | | -// ═══════════════════════════════════════ |
293 | | -// 2. SCROLL REVEAL (with stagger) |
294 | | -// ═══════════════════════════════════════ |
295 | | -const revealObs=new IntersectionObserver(entries=>{ |
296 | | - entries.forEach(e=>{if(e.isIntersecting){e.target.classList.add('vis');revealObs.unobserve(e.target)}}); |
297 | | -},{threshold:.12,rootMargin:'0px 0px -40px 0px'}); |
298 | | -document.querySelectorAll('.rv,.rv-left,.rv-right,.rv-scale').forEach(e=>revealObs.observe(e)); |
299 | | - |
300 | | -// ═══════════════════════════════════════ |
301 | | -// 3. COUNTER ANIMATION (on scroll) |
302 | | -// ═══════════════════════════════════════ |
303 | | -const countEls=document.querySelectorAll('[data-count]'); |
304 | | -const countObs=new IntersectionObserver(entries=>{ |
305 | | - entries.forEach(e=>{ |
306 | | - if(!e.isIntersecting)return; |
307 | | - countObs.unobserve(e.target); |
308 | | - const el=e.target; |
309 | | - const target=parseFloat(el.dataset.count); |
310 | | - const suffix=el.dataset.suffix||''; |
311 | | - const decimals=parseInt(el.dataset.decimals||'0'); |
312 | | - const duration=1200; |
313 | | - const start=performance.now(); |
314 | | - function tick(now){ |
315 | | - const t=Math.min((now-start)/duration,1); |
316 | | - const ease=1-Math.pow(1-t,3); |
317 | | - const val=ease*target; |
318 | | - el.textContent=(decimals>0?val.toFixed(decimals):Math.round(val))+suffix; |
319 | | - if(t<1)requestAnimationFrame(tick); |
320 | | - } |
321 | | - requestAnimationFrame(tick); |
322 | | - }); |
323 | | -},{threshold:.5}); |
324 | | -countEls.forEach(e=>countObs.observe(e)); |
325 | | - |
326 | | -// ═══════════════════════════════════════ |
327 | | -// 4. ANIMATED BAR FILLS (on scroll) |
328 | | -// ═══════════════════════════════════════ |
329 | | -const barEls=document.querySelectorAll('.bar-anim'); |
330 | | -const barObs=new IntersectionObserver(entries=>{ |
331 | | - entries.forEach(e=>{ |
332 | | - if(!e.isIntersecting)return; |
333 | | - barObs.unobserve(e.target); |
334 | | - const el=e.target; |
335 | | - requestAnimationFrame(()=>{ |
336 | | - el.classList.remove('bar-anim'); |
337 | | - el.style.width=el.dataset.bar; |
338 | | - }); |
339 | | - }); |
340 | | -},{threshold:.3}); |
341 | | -barEls.forEach(e=>barObs.observe(e)); |
342 | | - |
343 | | -// ═══════════════════════════════════════ |
344 | | -// 5. PARALLAX |
345 | | -// ═══════════════════════════════════════ |
346 | | -const parallaxEls=document.querySelectorAll('.parallax'); |
347 | | -let ticking=false; |
348 | | -function updateParallax(){ |
349 | | - const scrollTop=window.scrollY; |
350 | | - parallaxEls.forEach(el=>{ |
351 | | - const speed=parseFloat(el.dataset.speed||'.2'); |
352 | | - const rect=el.getBoundingClientRect(); |
353 | | - const offset=(rect.top+scrollTop)*speed; |
354 | | - el.style.transform='translateY('+(-offset*.15).toFixed(1)+'px)'; |
355 | | - }); |
356 | | - ticking=false; |
357 | | -} |
358 | | -window.addEventListener('scroll',()=>{if(!ticking){ticking=true;requestAnimationFrame(updateParallax)}},{passive:true}); |
359 | | - |
360 | | -// ═══════════════════════════════════════ |
361 | | -// 6. NAV SHRINK ON SCROLL |
362 | | -// ═══════════════════════════════════════ |
363 | | -const nav=document.querySelector('.nav'); |
364 | | -window.addEventListener('scroll',()=>{ |
365 | | - nav.classList.toggle('scrolled',window.scrollY>50); |
366 | | -},{passive:true}); |
367 | | - |
368 | | -// ═══════════════════════════════════════ |
369 | | -// 7. PM TOGGLE |
370 | | -// ═══════════════════════════════════════ |
371 | | -const cmds={ |
372 | | - bun:['bun install','bun run dev','bun run bench','bun run bench:report'], |
373 | | - pnpm:['pnpm install','pnpm dev','pnpm bench','pnpm bench:report'], |
374 | | - npm:['npm install','npm run dev','npm run bench','npm run bench:report'], |
375 | | - yarn:['yarn','yarn dev','yarn bench','yarn bench:report'], |
376 | | -}; |
377 | | -document.getElementById('pm-toggle').addEventListener('click',e=>{ |
378 | | - const btn=e.target.closest('.pm-btn');if(!btn)return; |
379 | | - const pm=btn.dataset.pm; |
380 | | - document.querySelectorAll('.pm-btn').forEach(b=>b.classList.remove('active')); |
381 | | - btn.classList.add('active'); |
382 | | - const c=cmds[pm]; |
383 | | - document.getElementById('cmd-install').textContent=c[0]; |
384 | | - document.getElementById('cmd-dev').textContent=c[1]; |
385 | | - document.getElementById('cmd-bench').textContent=c[2]; |
386 | | - document.getElementById('cmd-report').textContent=c[3]; |
387 | | -}); |
388 | | - |
389 | | -// ═══════════════════════════════════════ |
390 | | -// 8. SYNAPSE DEMO |
391 | | -// ═══════════════════════════════════════ |
392 | | -(async()=>{ |
393 | | - const canvas=document.getElementById('demo-canvas'); |
394 | | - if(!navigator.gpu){ |
395 | | - canvas.parentElement.innerHTML='<div class="demo-nope">WebGPU non disponible dans ce navigateur.<br>Utilisez Chrome 113+, Edge 113+ ou Firefox Nightly.</div>'; |
396 | | - return; |
397 | | - } |
398 | | - try{ |
399 | | - const{mountDemo}=await import('/src/landing.ts'); |
400 | | - await mountDemo(canvas); |
401 | | - }catch(err){ |
402 | | - console.error('Demo mount failed:',err); |
403 | | - document.getElementById('demo-fps').textContent='Erreur: '+err.message; |
404 | | - } |
405 | | -})(); |
406 | | -</script> |
| 310 | +<script type="module" src="/src/landing-main.ts"></script> |
407 | 311 | </body> |
408 | 312 | </html> |
0 commit comments