perf(home): transicoes de Qualidade so com translate/opacity e titulos por palavra em CSS
Medido com trace do Chromium (rasterizacao no mesmo trecho de rolagem): IA->Qualidade 840->558 ms, dentro de Qualidade 34->18 ms, Qualidade->Sobre 819->643 ms. Recorte animado, escala de camadas grandes e o desenho do diagrama a cada quadro saem; o diagrama se desenha uma vez em CSS. TextDiffuseReveal deixa de animar cada letra com desfoque. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
44efcfcb20
commit
def1e22302
5 files changed
+121
-215
No files matched your search
@@ -85,48 +85,27 @@ const TRANSITIONS: Transition[] = [
|
||||
0,
|
||||
);
|
||||
},
|
||||
// IA → qualidade: a tela se abre do centro como duas portas, e o diagrama se desenha.
|
||||
// Só 2D: com rotação 3D o Chrome adiava a pintura do diagrama (camada grande demais).
|
||||
// IA → qualidade: a seção sobe mais rápido que a rolagem, como um cartão, sobre a anterior que escurece.
|
||||
// Só translate/opacity: recorte animado, escala (o Chrome rasteriza de novo a cada novo tamanho) e o
|
||||
// desenho do diagrama a cada quadro dobravam o custo de pintura desta passagem. O diagrama se desenha
|
||||
// uma vez, em CSS, quando a passagem começa (classe is-drawing, ver onEnter).
|
||||
(tl, prev, next) => {
|
||||
holdPrev(tl, prev);
|
||||
holdNext(tl, next);
|
||||
tl.fromTo(
|
||||
prev,
|
||||
{ scale: 1, opacity: 1, transformOrigin: visibleCenter(prev) },
|
||||
{ scale: 0.9, opacity: 0.25 },
|
||||
0,
|
||||
).fromTo(
|
||||
tl.fromTo(prev, { opacity: 1 }, { opacity: 0.2 }, 0).fromTo(
|
||||
next,
|
||||
{ clipPath: () => `inset(0px 50% ${next.offsetHeight - vh()}px 50%)` },
|
||||
{ clipPath: () => `inset(0px 0% ${next.offsetHeight - vh()}px 0%)`, ease: "power2.inOut" },
|
||||
{ yPercent: 0, y: () => vh() * 0.35 },
|
||||
{ y: 0, ease: "power2.out" },
|
||||
0,
|
||||
);
|
||||
const lines = next.querySelectorAll(
|
||||
".quality-dimensions path, .quality-browser-frame, .quality-blueprint > path.quality-wire, .quality-blueprint > rect.quality-wire, .quality-blueprint > g.quality-wire > *, .quality-browser-button",
|
||||
);
|
||||
const labels = next.querySelectorAll(
|
||||
".quality-blueprint text, .quality-browser-dots, .quality-visual-label, .quality-visual figcaption",
|
||||
);
|
||||
if (lines.length) {
|
||||
tl.set(lines, { attr: { pathLength: 1 }, strokeDasharray: 1 }, 0).fromTo(
|
||||
lines,
|
||||
{ strokeDashoffset: 1 },
|
||||
{ strokeDashoffset: 0, duration: 0.4, stagger: { amount: 0.25 } },
|
||||
0.3,
|
||||
);
|
||||
}
|
||||
if (labels.length) {
|
||||
tl.fromTo(labels, { opacity: 0 }, { opacity: 1, duration: 0.25, stagger: { amount: 0.2 } }, 0.5);
|
||||
}
|
||||
},
|
||||
// qualidade → sobre: cortina diagonal
|
||||
// qualidade → sobre: a página entra girando pela esquerda, como uma folha virando (só transform)
|
||||
(tl, prev, next) => {
|
||||
holdPrev(tl, prev);
|
||||
holdNext(tl, next);
|
||||
tl.fromTo(prev, { opacity: 1, xPercent: 0 }, { opacity: 0.25, xPercent: 8 }, 0).fromTo(
|
||||
tl.fromTo(prev, { opacity: 1, xPercent: 0 }, { opacity: 0.25, xPercent: 20 }, 0).fromTo(
|
||||
next,
|
||||
{ clipPath: () => `polygon(0% 0px, 0% 0px, -30% ${vh()}px, -30% ${vh()}px)` },
|
||||
{ clipPath: () => `polygon(0% 0px, 130% 0px, 100% ${vh()}px, -30% ${vh()}px)` },
|
||||
{ xPercent: -100, rotation: -7, transformOrigin: "0% 0%" },
|
||||
{ xPercent: 0, rotation: 0, ease: "power2.out" },
|
||||
0,
|
||||
);
|
||||
},
|
||||
@@ -199,6 +178,8 @@ export function useCinematicScroll(mainRef: RefObject<HTMLElement | null>) {
|
||||
invalidateOnRefresh: true,
|
||||
// passagem concluída: o recorte já cobre a tela inteira; sem ele a seção pinta normalmente
|
||||
onLeave: () => gsap.set(next, { clipPath: "none" }),
|
||||
// diagrama de qualidade: desenha uma vez quando a seção começa a entrar
|
||||
onEnter: () => next.classList.add("is-drawing"),
|
||||
},
|
||||
});
|
||||
transition(tl, prev, next);
|
||||
|
||||
Reference in new issue
Block a user