perf(movimento): sem tempo morto, vídeos regravados e 3D sem React Three Fiber

Legenda do mergulho até Projetos cobrir a cena; transição de página sem blur e com fundo escuro; foco no conteúdo ao trocar de página; listas com marcador e dois pesos de título; vídeos da SEV e da SC Plus regravados sem quadros brancos; scrub a 12-15 fps (-30%); vitrine com uma parada de Tab e setas, contador no celular e CSS sob demanda; âncoras num módulo só (fragment-nav); FramePulse com setInterval; CSS morto removido.
This commit is contained in:
Evandro Fonseca Junior committed 2026-10-14 17:01:37 -03:00
1 parent f8545cd442
commit 6ac87824f3
68 files changed
+5735 -3300

No files matched your search

+9 -55
View File
@@ -2,6 +2,7 @@
import { type RefObject, useEffect } from "react";
import { isCoarsePointer, prefersReducedMotion } from "@/lib/device";
import { focusFragment, onFragmentClick } from "./fragment-nav";
/*
* Rolagem da home. Duas coisas, nenhuma delas com biblioteca de animação:
@@ -13,7 +14,8 @@ import { isCoarsePointer, prefersReducedMotion } from "@/lib/device";
* cena; nada aqui depende de uma seção específica existir.
* 2. Este hook cuida só do que o CSS não faz: no mouse, o Lenis suaviza a roda (com o relógio ligado apenas
* enquanto algo se move, nunca com a página parada), e os links internos (#id) "avançam o vídeo" até o
* destino em vez de saltar. No toque a rolagem nativa corre em outra thread: nem o Lenis é baixado.
* destino em vez de saltar (o clique vem de fragment-nav). No toque a rolagem nativa corre em outra thread:
* nem o Lenis é baixado.
*
* As únicas rolagens "presas" são as do CSS: o hero (sticky) e a vitrine de projetos (sticky).
*/
@@ -49,50 +51,6 @@ export function anchorDuration(distance: number, viewport: number) {
const easeInOutCubic = (t: number) =>
t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
/** Clique do botão principal, sem tecla modificadora, que nenhum outro código já tratou. */
export function isPlainPrimaryClick(event: MouseEvent) {
return !(
event.defaultPrevented ||
event.button !== 0 ||
event.metaKey ||
event.ctrlKey ||
event.shiftKey ||
event.altKey
);
}
/** O link (<a>) que o clique atingiu, se abre na mesma aba; `null` para qualquer outro clique. */
function sameTabLink(event: MouseEvent) {
const link =
event.target instanceof Element ? event.target.closest("a[href]") : null;
if (!(link instanceof HTMLAnchorElement)) return null;
return !link.target || link.target === "_self" ? link : null;
}
/** O `#id` de um link para esta mesma página; `null` se ele leva a outra página ou não tem âncora. */
function hashOnThisPage(link: HTMLAnchorElement) {
const url = new URL(link.href);
const same =
url.origin === location.origin && url.pathname === location.pathname;
return same && url.hash ? url.hash : null;
}
function elementForHash(hash: string) {
try {
return document.getElementById(decodeURIComponent(hash.slice(1)));
} catch {
return null;
}
}
/** Link para outro ponto da MESMA página (`#id`): o elemento de destino e o hash; `null` para qualquer outro clique. */
export function samePageHashTarget(event: MouseEvent) {
const link = sameTabLink(event);
const hash = link && hashOnThisPage(link);
const target = hash ? elementForHash(hash) : null;
return hash && target ? { target, hash } : null;
}
/**
* Posição da rolagem (px) para mostrar `target`: o alvo que é a cena inteira para no topo dela; um alvo
* interno desconta o cabeçalho fixo, sem passar do topo da cena.
@@ -181,25 +139,21 @@ export function useCinematicScroll(mainRef: RefObject<HTMLElement | null>) {
});
};
// botões e links internos: em vez do salto, a página "avança o vídeo" (de pouco) até o destino
const onClick = (event: MouseEvent) => {
if (!isPlainPrimaryClick(event)) return;
const hit = samePageHashTarget(event);
if (!hit) return;
// botões e links internos: em vez do salto, a página "avança o vídeo" (de pouco) até o destino. O clique
// chega já interpretado por fragment-nav (o único ouvinte de clique das âncoras).
const stopClicks = onFragmentClick((hit, event) => {
event.preventDefault();
if (location.hash !== hit.hash) history.pushState(null, "", hit.hash);
scrollToTop(
anchorTop(hit.target, Array.from(main.children) as HTMLElement[]),
);
// o foco vai junto: a cena já está no fluxo, visível e pronta para recebê-lo
if (!hit.target.hasAttribute("tabindex")) hit.target.tabIndex = -1;
hit.target.focus({ preventScroll: true });
};
document.addEventListener("click", onClick, true);
focusFragment(hit.target);
});
return () => {
cancelled = true;
document.removeEventListener("click", onClick, true);
stopClicks();
smooth?.destroy();
};
}, [mainRef]);