perf(movimento): vitrine e 3D mais leves, WebGL por software lembrado na sessão e suporte ao WebKit

This commit is contained in:
Evandro Fonseca Junior committed 2026-10-14 22:54:27 -03:00
1 parent 9fd1570426
commit 8903f3c57e
28 files changed
+854 -406

No files matched your search

+21 -23
View File
@@ -1,4 +1,5 @@
import { act, render, screen } from "@testing-library/react";
import { rememberSoftwareWebGL } from "@/lib/device";
import HeroField, { DIVE_QUERY } from "./HeroField";
type SceneProps = {
@@ -38,18 +39,6 @@ function mockMedia(active: string[] = [DIVE_QUERY]) {
}));
}
/** Um WebGL2 que abre, e que diz na extensão de depuração em que renderizador desenha. */
function mockWebGLRenderer(renderer: string) {
HTMLCanvasElement.prototype.getContext = (() => ({
getExtension: (name: string) =>
name === "WEBGL_debug_renderer_info"
? { UNMASKED_RENDERER_WEBGL: 37446 }
: null,
getParameter: (parameter: number) =>
parameter === 37446 ? renderer : null,
})) as unknown as typeof HTMLCanvasElement.prototype.getContext;
}
function mockNavigator(values: Record<string, unknown>) {
for (const [key, value] of Object.entries(values))
Object.defineProperty(navigator, key, { configurable: true, value });
@@ -94,6 +83,7 @@ async function idle() {
beforeEach(() => {
jest.useFakeTimers();
sessionStorage.clear();
mockScenes.length = 0;
mockPrepare.mockClear();
mockMedia();
@@ -111,6 +101,7 @@ beforeEach(() => {
afterEach(() => {
jest.useRealTimers();
sessionStorage.clear();
window.matchMedia = original.matchMedia;
(window as unknown as Record<string, unknown>).WebGL2RenderingContext =
original.webgl2;
@@ -129,6 +120,19 @@ describe("HeroField (ambient background)", () => {
expect(mockScenes.at(-1)?.visible).toBe(true);
});
it("opens no WebGL context of its own, on hydration or when idle: the only one is the scene's", async () => {
const probe = jest.fn(() => ({ getExtension: () => null }));
HTMLCanvasElement.prototype.getContext =
probe as unknown as typeof HTMLCanvasElement.prototype.getContext;
render(<Hero />);
expect(probe).not.toHaveBeenCalled();
await idle();
expect(probe).not.toHaveBeenCalled();
expect(screen.getByTestId("scene")).toBeInTheDocument();
});
it("brings the geometry in before the Canvas, in a task of its own", async () => {
render(<Hero />);
@@ -183,17 +187,11 @@ describe("HeroField (ambient background)", () => {
undefined;
},
],
...[
"ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)",
"llvmpipe (LLVM 15.0.7, 256 bits)",
"ANGLE (Microsoft, Microsoft Basic Render Driver (0x0000008C) Direct3D11 vs_5_0 ps_5_0, D3D11)",
].map(
(renderer) =>
[
`software WebGL (${renderer.slice(0, 24)}...)`,
() => mockWebGLRenderer(renderer),
] as [string, () => void],
),
// o veredito vem do contexto da cena (HeroFieldScene), que o anota na sessão; a página seguinte já nasce estática
[
"a software WebGL found earlier in the session",
() => rememberSoftwareWebGL(),
],
])(
"keeps the light static background (no WebGL, no dive, no scroll work) with %s",
async (_label, arrange) => {