Files
portifolio-evandrodevbr/app/components/cinematic/FramePulse.tsx
T
Evandro Fonseca Junior c9a0b80656 perf(movimento): uma transição, 3D leve e vídeo certo por aparelho
Passagens com fade e 32 px, cena anterior termina em opacidade 0, sem visibility nem clip-path. 3D do hero como fundo ambiente, sob demanda e desligado em toque, aparelho fraco, saveData e movimento reduzido. Lenis fora do toque e salto direto em âncoras distantes. Vitrine só de clientes, até 3 capítulos, fixa só no desktop e carrossel no celular; vídeo só do projeto em cena com preload metadata. Rótulos mono a partir de 12 px e limão só no contato.
2026-10-14 03:32:23 -03:00

37 lines
1004 B
TypeScript

"use client";
import { useThree } from "@react-three/fiber";
import { useEffect } from "react";
/**
* Batida das cenas WebGL em `frameloop="demand"`: enquanto `active`, pede um quadro a no máximo `fps` por
* segundo (fundo ambiente, sem gastar 60 quadros por segundo); com `active` falso, nenhum quadro é desenhado.
* Quem precisa de mais (entrada, rolagem, cursor) pede o próximo quadro com `invalidate()` dentro do useFrame.
*/
export default function FramePulse({
active,
fps = 30,
}: {
active: boolean;
fps?: number;
}) {
const invalidate = useThree((state) => state.invalidate);
useEffect(() => {
if (!active) return;
const gap = 1000 / fps - 2;
let id = 0;
let last = 0;
const beat = (now: number) => {
id = requestAnimationFrame(beat);
if (now - last < gap) return;
last = now;
invalidate();
};
id = requestAnimationFrame(beat);
return () => cancelAnimationFrame(id);
}, [active, fps, invalidate]);
return null;
}