Un site 3D poate fi rapid și complet indexabil dacă scena 3D e tratată ca un strat peste HTML pre-⁠randat, nu ca pagina însăși. Pe bitnoda.team, fiecare rută e pre-⁠randată ca HTML static cu vite-ssg, iar three.js se încarcă abia după ce pagina e vizibilă, doar pe dispozitivele care îl pot rula. Măsurat pe build-⁠ul de producție pe 29 septembrie 2026: prima încărcare a paginii principale are nevoie de circa 92 KB de JavaScript comprimat, iar cei aproximativ 228 KB de cod 3D vin mai târziu.

Problema site-⁠urilor 3D

Multe site-⁠uri 3D își desenează tot conținutul într-⁠un canvas, din JavaScript. Pentru un om cu un laptop puternic arată bine. Pentru un crawler, pagina e aproape goală: fără titluri, fără text, fără linkuri.

Asta contează mai mult acum decât acum câțiva ani: multe crawlere ale asistenților AI nu rulează JavaScript deloc. Ce nu e în HTML, pentru ele nu există. Iar pe telefoanele obișnuite, un site care descarcă întâi tot motorul 3D se încarcă greu și consumă bateria.

Pasul 1: conținutul e întâi HTML

Toate paginile bitnoda.team sunt pre-⁠randate la build cu vite-ssg, în ambele limbi: titlul, H1-⁠ul, textul, linkurile și datele structurate JSON-LD sunt deja în HTML-⁠ul trimis de server. Scena 3D nu poartă niciun fapt care nu e și în text.

Pe server, locul scenei îl ține un poster făcut din CSS și SVG. Pagina e completă și utilă chiar dacă 3D-⁠ul nu pornește niciodată.

Pasul 2: 3D-⁠ul se încarcă ultimul

Codul 3D (three.js, regizorul scenei, încărcătorul de modele) se importă dinamic și doar după trei condiții: evenimentul load, prima afișare și un moment liber al browserului. Pe telefoane așteptăm în plus prima interacțiune reală a vizitatorului, ca să nu plătim three.js pentru cine doar citește.

Un detaliu ușor de ratat: bundler-⁠ul adaugă implicit modulepreload și pentru chunk-⁠urile importate dinamic, deci browserul le-⁠ar descărca oricum la început. Configurația Vite de pe acest site elimină la build acele preload-⁠uri pentru chunk-⁠urile atinse doar prin import dinamic.

Pasul 3: decizia se ia pe dispozitiv

Un modul mic, fără three.js, estimează nivelul dispozitivului (ridicat, mediu, scăzut) înainte de a descărca ceva greu. Dispozitivele de nivel scăzut rămân pe varianta statică. Celelalte primesc o rezoluție de randare limitată pe nivel, iar scena se oprește când iese din ecran.

Pentru că telefoanele diferă enorm, regizorul scenei măsoară timpul fiecărui cadru și coboară calitatea dacă cadrele devin lente, în loc să sacadeze. Dacă browserul pierde contextul WebGL, pagina revine la varianta statică.

Pasul 4: un singur ceas, sarcini scurte

Scroll-⁠ul lin (Lenis), sincronizarea cu scroll-⁠ul, timeline-⁠ul animației, personajele și randarea rulează dintr-⁠un singur ceas, ticker-⁠ul GSAP, nu din bucle separate care se calcă pe picioare.

Construirea scenei e împărțită în bucăți: între pași, codul cedează controlul browserului (scheduler.yield unde există). Scopul e ca nicio sarcină să nu treacă de circa 50 ms, pragul de la care browserele o numesc „sarcină lungă” și pagina pare înghețată.

Cifrele

Măsurate pe build-⁠ul de producție al bitnoda.team, pe 29 septembrie 2026, cu compresie gzip:

  • Prima încărcare a paginii principale: 10 fișiere JavaScript, circa 92 KB comprimat.
  • Codul 3D, care nu intră în prima încărcare: chunk-⁠ul three.js circa 167 KB, regizorul scenei circa 48 KB, încărcătorul glTF circa 13 KB, adică aproximativ 228 KB în total.
  • Modelul personajului: un fișier glTF comprimat cu meshopt, de circa 157 KB.

Ce înseamnă asta pentru proiectul tău

Aceleași reguli le folosim când construim site-⁠uri 3D și configuratoare 3D de produs: conținutul în HTML, 3D-⁠ul ca strat, decizia pe dispozitiv și bugete de performanță urmărite pe tot proiectul. Stack-⁠ul e cel din dezvoltarea Nuxt și Vue.

Surse

  1. Vercel: The rise of the AI crawler (crawlerele AI și JavaScript)(se deschide într-o filă nouă)
  2. vite-ssg: generare statică pentru Vue(se deschide într-o filă nouă)
  3. meshoptimizer: compresie pentru modele glTF(se deschide într-o filă nouă)