perf(movimento): vitrine e 3D mais leves, WebGL por software lembrado na sessão e suporte ao WebKit
This commit is contained in:
1 parent
9fd1570426
commit
8903f3c57e
28 files changed
+854
-406
No files matched your search
@@ -7,7 +7,7 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { isLowPowerDevice, isSoftwareWebGL } from "@/lib/device";
|
||||
import { isKnownSoftwareWebGL, isLowPowerDevice } from "@/lib/device";
|
||||
import type { HeroFieldSceneProps } from "./HeroFieldScene";
|
||||
|
||||
/** A mesma condição do CSS do mergulho (globals.css): tela com altura para o conteúdo e sem movimento reduzido. */
|
||||
@@ -44,21 +44,12 @@ const smooth = (a: number, b: number, x: number) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* O aparelho abre um contexto WebGL2 de verdade, na GPU. Um WebGL por software (SwiftShader, llvmpipe, Microsoft
|
||||
* Basic Render) abre, mas desenha a cena a poucos quadros por segundo na CPU: nesse caso vale o hero estático.
|
||||
* O navegador tem a API do WebGL2? É só uma leitura: abrir um contexto de teste aqui, na hidratação, custava uma tarefa
|
||||
* de 150 ms (500 ms por software). Se o WebGL2 abre de verdade, e se ele desenha na GPU, quem diz é a própria cena,
|
||||
* no contexto que ela abre para desenhar (HeroFieldScene.createRenderer); o veredito "por software" fica anotado na
|
||||
* sessão (isKnownSoftwareWebGL), e as páginas seguintes já nascem estáticas.
|
||||
*/
|
||||
function supportsWebGL2() {
|
||||
if (typeof window.WebGL2RenderingContext === "undefined") return false;
|
||||
try {
|
||||
const context = document.createElement("canvas").getContext("webgl2");
|
||||
if (!context) return false;
|
||||
const software = isSoftwareWebGL(context);
|
||||
context.getExtension("WEBGL_lose_context")?.loseContext();
|
||||
return !software;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const hasWebGL2 = () => typeof window.WebGL2RenderingContext !== "undefined";
|
||||
|
||||
/** Um intervalo ocioso do navegador (sem requestIdleCallback, um instante depois). */
|
||||
function nextIdle() {
|
||||
@@ -183,7 +174,9 @@ function trackVisibility(
|
||||
* outros o hero é só o palco de 100svh com o fundo estático leve do CSS (.hero-glow), sem ouvinte de rolagem
|
||||
* e sem baixar o Three.js. No aparelho capaz, a cena WebGL entra na primeira interação ou quando a página fica
|
||||
* ociosa com folga, em passos separados (pacote, geometria, Canvas); a rolagem do hero conduz o mergulho
|
||||
* (trackDive). Sem legendas sobre o 3D: o espaço da direita é das molduras.
|
||||
* (trackDive). O desenho por software só se descobre no contexto que a cena abre (nunca num contexto de teste na
|
||||
* hidratação): ela avisa por `onError` e o hero volta ao palco estático. Sem legendas sobre o 3D: o espaço da direita
|
||||
* é das molduras.
|
||||
*/
|
||||
export default function HeroField() {
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
@@ -202,9 +195,10 @@ export default function HeroField() {
|
||||
if (isLowPowerDevice()) return;
|
||||
const section = rootRef.current?.closest<HTMLElement>(".hero");
|
||||
if (!section) return;
|
||||
// WebGL2 só por software (ou nenhum): o hero estático de 100svh, já na hidratação, sem o bloco de rolagem do
|
||||
// mergulho que depois seria desfeito com a página já rolada
|
||||
if (!supportsWebGL2()) return;
|
||||
// sem WebGL2, ou com o desenho por software já descoberto nesta sessão: o hero estático de 100svh, já na hidratação,
|
||||
// sem o bloco de rolagem do mergulho. Num aparelho ainda não testado o mergulho liga já (o veredito sai do contexto
|
||||
// da cena, ocioso, sem uma tarefa longa na hidratação); sendo software, a cena avisa e o hero volta a 100svh
|
||||
if (!hasWebGL2() || isKnownSoftwareWebGL()) return;
|
||||
let alive = true;
|
||||
const stopDive = window.matchMedia?.(DIVE_QUERY).matches
|
||||
? trackDive(section, progressRef, setDone)
|
||||
|
||||
Reference in new issue
Block a user