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:
1 parent
f8545cd442
commit
6ac87824f3
68 files changed
+5735
-3300
No files matched your search
@@ -0,0 +1,55 @@
|
||||
/** Gestos que mostram alguém olhando para a página: qualquer um deles religa a batida. */
|
||||
const ACTIVITY = [
|
||||
"pointermove",
|
||||
"pointerdown",
|
||||
"scroll",
|
||||
"wheel",
|
||||
"touchmove",
|
||||
"keydown",
|
||||
] as const;
|
||||
|
||||
export type FramePulseOptions = {
|
||||
/** Quadros por segundo pedidos (padrão 30). */
|
||||
fps?: number;
|
||||
/** Tempo (ms) sem cursor, rolagem nem teclado depois do qual a batida para de vez (padrão 5000). */
|
||||
idleMs?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Batida das cenas WebGL em demanda: pede um quadro (`invalidate`) a no máximo `fps` por segundo, de um único
|
||||
* `setInterval` (fundo ambiente, sem gastar 60 quadros por segundo e sem um segundo laço de requestAnimationFrame ao
|
||||
* lado do da cena). Depois de `idleMs` sem cursor, rolagem nem teclado, a batida para de vez (nenhum intervalo, nenhum
|
||||
* quadro) e o último quadro fica na tela; qualquer movimento a religa. Quem precisa de mais (entrada, rolagem, cursor)
|
||||
* pede o próximo quadro por conta própria, dentro do quadro. Devolve a função que desliga tudo.
|
||||
*/
|
||||
export function startFramePulse(
|
||||
invalidate: () => void,
|
||||
{ fps = 30, idleMs = 5000 }: FramePulseOptions = {},
|
||||
) {
|
||||
const period = Math.round(1000 / fps);
|
||||
let timer: ReturnType<typeof setInterval> | undefined;
|
||||
let lastActivity = performance.now();
|
||||
|
||||
const stopTimer = () => {
|
||||
clearInterval(timer);
|
||||
timer = undefined;
|
||||
};
|
||||
const beat = () => {
|
||||
// parada por inatividade: sem intervalo até o próximo movimento
|
||||
if (performance.now() - lastActivity > idleMs) stopTimer();
|
||||
else invalidate();
|
||||
};
|
||||
const wake = () => {
|
||||
lastActivity = performance.now();
|
||||
if (timer === undefined) timer = setInterval(beat, period);
|
||||
};
|
||||
|
||||
for (const type of ACTIVITY)
|
||||
window.addEventListener(type, wake, { passive: true });
|
||||
wake();
|
||||
invalidate();
|
||||
return () => {
|
||||
for (const type of ACTIVITY) window.removeEventListener(type, wake);
|
||||
stopTimer();
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user