Obiettivi della lezione
Adesso i due pezzi si attaccano. La scena della Lezione 4, vestita come nella 5, comandata dal dito con gli strumenti della 3. Da qui esce la cosa che il cliente aveva in mente quando ha detto «lo voglio 3D».
Alla fine sei capace di:
- Far animare a GSAP le proprietà di un oggetto Three, che non sono CSS;
- Tenere il canvas fermo mentre il contenuto scorre sopra;
- Muovere la camera lungo un percorso legato allo scorrimento;
- Ridisegnare solo quando serve, invece che sessanta volte al secondo per sempre;
- Far restare la pagina leggibile quando il 3D non parte.
L'aggancio, che è più semplice di quanto sembri
GSAP non anima solo il CSS: anima le proprietà numeriche di qualunque oggetto JavaScript. E la rotazione di un mesh è un oggetto JavaScript con dentro tre numeri. Quindi non serve niente di speciale.
gsap.to(cubo.rotation, {
y: Math.PI * 2, // un giro intero, in radianti
ease: "none", // con scrub l'ease lo fa il dito
scrollTrigger: {
trigger: ".sezione-prodotto",
start: "top top",
end: "bottom bottom",
scrub: 0.6
}
});
Tre cose da tenere a mente. Gli angoli sono in radianti, quindi un giro è Math.PI * 2 e un quarto di giro è Math.PI / 2. Le posizioni sono in unità della scena, che valgono quello che hai deciso tu quando hai messo la camera. E scrub resta la chiave: senza, l'animazione parte e va per conto suo, e il senso di comandare la scena sparisce.
Il canvas fermo, il contenuto che scorre
L'impaginazione di quasi tutti i siti 3D è una sola, e si fa in CSS senza bisogno di pin: il canvas sta fisso a schermo intero, dietro; il contenuto scorre sopra in sezioni alte quanto lo schermo.
#vista {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.contenuto { position: relative; z-index: 1; }
.contenuto section { min-height: 100vh; display: grid; place-items: center; }
Il vantaggio rispetto al pin della Lezione 3 è che qui non c'è niente da bloccare: il canvas è già fermo, e ScrollTrigger deve solo dire alla scena a che punto siamo. Meno cose che si rompono, e sul telefono si comporta meglio.
Il testo sopra al 3D va reso leggibile
Un testo bianco sopra a una scena che cambia colore mentre scorri è leggibile in tre sezioni su cinque. Si risolve con un velo dietro al testo o con un'ombra: un text-shadow largo e poco opaco, oppure un pannello con lo sfondo semitrasparente. Sembra un dettaglio e invece è la differenza fra un sito che si legge e uno che si guarda e basta.
Muovere la camera
Girare l'oggetto è l'effetto più semplice. Muovere la camera è quello che dà l'idea di attraversare uno spazio, ed è il passo successivo.
const t = gsap.timeline({
scrollTrigger: {
trigger: ".contenuto",
start: "top top",
end: "bottom bottom",
scrub: 0.8,
onUpdate: () => { daRidisegnare = true; } // vedi la sezione dopo
}
});
t.to(camera.position, { x: 0, y: 1, z: 3 }) // dalla panoramica al dettaglio
.to(camera.position, { x: -2, y: 0.5, z: 2 }) // gira attorno
.to(camera.position, { x: 0, y: 3, z: 6 }); // si allontana per chiudere
// la camera deve guardare qualcosa, e va detto a ogni fotogramma
function guarda() { camera.lookAt(0, 0, 0); }
Attenzione a lookAt: è un ordine che vale una volta, non una proprietà che resta. Se muovi la camera e non lo ripeti, la camera trasla restando girata come prima. Va richiamato dentro al giro di disegno, dopo aver aggiornato la posizione.
Un consiglio che vale le tre ore che fa risparmiare: lavora sui numeri con i controlli del mouse accesi. Aggiungi OrbitControls, gira attorno alla scena finché non trovi l'inquadratura che vuoi, stampa camera.position in console, e copia quei numeri nella timeline. Trovare le coordinate a occhio scrivendole a mano è il modo lento.
Ridisegnare solo quando serve
Nella Lezione 4 il giro ridisegnava sempre, perché il cubo girava sempre. Adesso la scena cambia solo quando qualcuno scorre: se ridisegni lo stesso identico fotogramma sessanta volte al secondo mentre la persona legge, stai scaldando il telefono per niente.
let daRidisegnare = true;
renderer.setAnimationLoop(() => {
if (!daRidisegnare) return;
camera.lookAt(0, 0, 0);
renderer.render(scena, camera);
daRidisegnare = false;
});
// e ogni cosa che cambia la scena alza la mano:
// negli ScrollTrigger: onUpdate: () => { daRidisegnare = true; }
// al ridimensionamento: dentro adatta()
window.addEventListener('resize', () => { adatta(); daRidisegnare = true; });
È una decina di righe e cambia il comportamento della pagina: ferma consuma quanto una pagina normale, e si accende solo mentre si scorre. Su un portatile si sente dalla ventola, sul telefono dalla mano.
E quando la scena non si vede
Se il canvas esce dallo schermo o la scheda finisce in secondo piano, tanto vale fermarsi del tutto. Per la scheda ci pensa setAnimationLoop da solo; per il canvas fuori vista serve un IntersectionObserver che spenga e riaccenda il giro. Nella Lezione 7 lo usiamo anche per caricare la scena in ritardo.
Quando il 3D non parte
Questa è la parte che si scrive adesso e non alla fine, perché alla fine non la scrive nessuno. La pagina deve dire quello che deve dire anche senza il canvas: chi ha WebGL spento, chi ha una scheda in lista nera, chi ha una connessione che non porta a casa il modello, e i motori di ricerca, che nel tuo canvas non vedono niente.
La regola è quella della Lezione 1: il contenuto sta nell'HTML, il 3D è un di più. In pratica:
- Titoli, testi e immagini stanno nelle sezioni, e si leggono da soli.
- Il canvas ha un'immagine di scorta dietro, che si vede se la scena non parte.
- Il codice controlla se WebGL c'è prima di provarci, e se non c'è lascia stare in silenzio.
function webglCePer(canvas) {
try { return !!(window.WebGLRenderingContext && canvas.getContext('webgl2')); }
catch (e) { return false; }
}
if (!webglCePer(document.querySelector('#vista'))) {
document.querySelector('#vista').hidden = true; // resta l'immagine di scorta
} else {
avviaLaScena();
}
Laboratorio: il tuo sito 3D
Obiettivo: la pagina del tuo progetto con la scena legata allo scorrimento, e la stessa pagina che si legge senza.
Consegna
- Monta l'impianto: canvas fisso a schermo intero, tre o quattro sezioni alte quanto lo schermo che scorrono sopra, con dentro i testi veri del tuo progetto.
- Lega la rotazione del tuo oggetto allo scorrimento con
scrub, su tutta la pagina. - Trova le inquadrature con
OrbitControlsaccesi, segnati tre posizioni di camera e mettile in una timeline. - Passa al disegno a richiesta e verifica con il pannello delle prestazioni che da fermo non si disegni niente.
- Rendi leggibile il testo sopra alla scena in tutte le sezioni, anche quelle dove il fondo è chiaro.
- Spegni WebGL nel browser e ricarica: la pagina deve restare leggibile e sensata, con l'immagine di scorta al posto della scena.
- Guardala a 390px di larghezza e decidi che cosa fare: spesso sul telefono la scena resta ferma e scorre solo il contenuto.
Risultato atteso
Una pagina dove scendere fa girare e attraversare, che da ferma non consuma, e che con WebGL spento è ancora una pagina che si legge. L'ultima prova è la più importante delle tre: se spegnendo il canvas resta una pagina vuota con quattro titoli in mezzo al niente, il 3D era l'unica cosa che c'era.
Mini-test di autoverifica
Istruzioni
Sezione A: 6 domande a risposta multipla (1 punto). Sezione B: 2 domande aperte (3 punti). Totale 12. Soglia: 60% (8/12).
Sezione A: risposta multipla
- GSAP può animare
cubo.rotation.yperché:
a) ha un plugin per Three b) anima le proprietà numeriche di qualunque oggetto c) lo converte in CSS d) non può - Un giro intero, in radianti, è:
a) 360 b)Math.PI * 2c)Math.PId) 1 - Per tenere il canvas fermo mentre il contenuto scorre:
a) servepinb) bastaposition: fixedin CSS c) serve un iframe d) non si può camera.lookAt:
a) è una proprietà che resta b) va richiamato dopo ogni spostamento c) si usa una volta sola all'avvio d) lo fa GSAP- Il disegno a richiesta serve a:
a) migliorare la grafica b) non ridisegnare lo stesso fotogramma mentre nessuno scorre c) caricare prima d) supportare il mobile - Il controllo su WebGL va fatto:
a) alla fine del progetto b) prima di provare ad avviare la scena c) solo su mobile d) non serve
Sezione B: risposta aperta
- (3 punti) Descrivi le sezioni della tua pagina e, per ognuna, che cosa fa la scena mentre la attraversi.
- (3 punti) Che cosa vede chi apre la tua pagina con WebGL spento? Elenca quello che resta e di' se basta a capire il messaggio.
Mostra risposte corrette
Sezione A
- b: anima numeri dentro a oggetti JavaScript, e
rotationè uno di quelli. - b:
Math.PI * 2. - b: basta il CSS, e si rompe meno del
pin. - b: è un ordine che vale una volta, quindi si ripete nel giro di disegno.
- b: da fermi non c'è niente di nuovo da disegnare.
- b: prima, così chi non ce l'ha resta con la pagina leggibile.
Sezione B, risposte modello
7. Esempio: sezione 1, il prodotto intero visto da lontano mentre compare il titolo; sezione 2, la camera si avvicina al dettaglio della chiusura mentre il testo la descrive; sezione 3, l'oggetto compie mezzo giro e si vede il retro con gli attacchi; sezione 4, la camera si allontana e resta il pulsante.
8. Restano i quattro titoli, i quattro paragrafi, le tre foto di scorta e il pulsante. Basta a capire che cos'è il prodotto, quanto costa e come si compra; quello che si perde è il retro, che infatti è anche in una delle foto.
Valutazione (su 12)
- 11-12: ottimo. 8-10: sufficiente. < 8: rivedi l'aggancio con
scrube il disegno a richiesta.
Riassunto della lezione
Cosa hai imparato
- GSAP anima le proprietà di Three senza niente in mezzo, perché sono numeri in oggetti.
- Canvas fisso e contenuto che scorre sopra: l'impianto si fa in CSS, senza
pin. lookAtva ripetuto dopo ogni spostamento della camera.- Le inquadrature si trovano con i controlli del mouse e si copiano, invece di indovinarle.
- Si ridisegna solo quando qualcosa cambia: da fermi la pagina deve costare come una pagina normale.
- Il ripiego si scrive adesso, perché alla fine non lo scrive nessuno.
Prossimi passi
Nella Lezione 7, Peso, prestazioni e chi resta fuori si misura: quanto pesa davvero, quante chiamate fa, che cosa succede su un telefono di quattro anni fa, e come si mette online senza far male alla velocità del sito.
Vuoi costruirlo sul tuo prodotto, con me accanto?
Porto questi percorsi in azienda e in presenza a Livorno: si arriva con il proprio caso e si esce con la pagina che gira.