From 7ecfd04f35809b44eb2f073b4b305c91252286a0 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 3 Feb 2026 01:47:43 +0000 Subject: [PATCH] perf(GradientBlinds): defer getBoundingClientRect to rAF on resize Optimizes `GradientBlinds` layout performance by using `ResizeObserverEntry.contentRect` for immediate renderer resizing and deferring the expensive `getBoundingClientRect()` call (required for mouse interaction mapping) to the next animation frame. This prevents synchronous layout thrashing inside the `ResizeObserver` callback. - Updates `resize` to accept `ResizeObserverEntry[]` - Uses `contentRect` for `renderer.setSize` - Defers `rectRef` update to `requestAnimationFrame` Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com> --- src/components/effects/GradientBlinds.tsx | 28 +++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/components/effects/GradientBlinds.tsx b/src/components/effects/GradientBlinds.tsx index 9f3b787..7550beb 100644 --- a/src/components/effects/GradientBlinds.tsx +++ b/src/components/effects/GradientBlinds.tsx @@ -280,18 +280,36 @@ void main() { const mesh = new Mesh(gl, { geometry, program }); meshRef.current = mesh; - const resize = () => { - const rect = container.getBoundingClientRect(); - rectRef.current = rect; + const resize = (entries?: ResizeObserverEntry[]) => { + let width, height; + + if (entries && entries.length > 0) { + const entry = entries[0]; + width = entry.contentRect.width; + height = entry.contentRect.height; + // Optimization: Defer calling getBoundingClientRect (which forces layout) + // to the next frame, since ResizeObserver runs after layout but before paint. + requestAnimationFrame(() => { + if (rendererRef.current) { + rectRef.current = container.getBoundingClientRect(); + } + }); + } else { + const rect = container.getBoundingClientRect(); + rectRef.current = rect; + width = rect.width; + height = rect.height; + } + if (typeof window !== 'undefined') { isMobileRef.current = window.innerWidth <= 768; scrollPosRef.current = { x: window.scrollX, y: window.scrollY }; } - renderer.setSize(rect.width, rect.height); + renderer.setSize(width, height); uniforms.iResolution.value = [gl.drawingBufferWidth, gl.drawingBufferHeight, 1]; if (blindMinWidth && blindMinWidth > 0) { - const maxByMinWidth = Math.max(1, Math.floor(rect.width / blindMinWidth)); + const maxByMinWidth = Math.max(1, Math.floor(width / blindMinWidth)); const effective = blindCount ? Math.min(blindCount, maxByMinWidth) : maxByMinWidth; uniforms.uBlindCount.value = Math.max(1, effective);