Back to Blog
Web Engineering5 min read

The Architecture Decision That Cut Our Site's Heavy Background Payload by ~180 KB

A step-by-step look at how we lazy-loaded a 180 KB Three.js scene in Next.js without losing the visual impact or hurting Core Web Vitals.

Webvoid EngineeringAugust 8, 20265 min read
TL;DR

Quick Summary

We replaced eager loading of a ~180 KB Three.js background with a Next.js dynamic import using ssr: false, keeping the animation while protecting first paint.

We cut our site's background payload by approximately 180 KB by replacing eager loading of a Three.js particle scene with a Next.js dynamic import set to ssr: false. This kept the animation for desktop users while preventing it from blocking the initial page render and hurting Core Web Vitals.

The Problem: A Visually Rich Hero with a Heavy Tax

Modern marketing sites compete on first impression. A dark mode, particle-filled hero looks premium. But that premium feel often comes with a JavaScript tax. In our case, the Three.js scene was ~180 KB of compressed JavaScript — a meaningful chunk for a page whose first job is to explain what we do in under 3 seconds.

Why 180 KB Matters for First Paint

On a 3G connection or a budget Android phone, 180 KB of JavaScript is not instant. It has to be downloaded, parsed, and executed before the browser can finish rendering. If that code is in the critical path, it delays LCP. If it runs on the server during SSR, it can also slow time-to-first-byte.

The Fix: Dynamic Import with SSR Disabled

We used Next.js dynamic imports so the background is not included in the server-rendered HTML, loads on the client only after the critical content is visible, and the main bundle stays lighter, protecting LCP and INP.

The Numbers We Targeted

We aligned the change with explicit Core Web Vitals targets: LCP under 2.5 seconds, CLS under 0.1, and INP under 200 milliseconds. Lazy-loading the background was one of several moves. Others included preconnecting to Google Fonts, lazy-loading below-fold sections, and structuring FAQ content with schema markup.

Lessons for Founders Building Visually Ambitious Sites

Visual polish and performance are not mutually exclusive. The trick is separating critical content from decorative enhancements and loading each on the right schedule. If an asset does not need to be there on first paint, do not put it there.

Frequently Asked Questions

What is lazy loading in Next.js?

Lazy loading delays loading a component or module until it is needed. In Next.js, you use dynamic() to split code and optionally disable server-side rendering.

Why disable SSR for a background animation?

Three.js and WebGL do not run on the server. Disabling SSR avoids unnecessary server work and hydration mismatches while still delivering the effect to users.

Does lazy loading hurt the user experience?

No, if done well. We kept the animation; we just deferred it until after the critical content loaded.

How do I know if an asset is blocking first paint?

Use Chrome DevTools Performance panel or Lighthouse. Look for long JavaScript execution and large resources loaded before the Largest Contentful Paint.

Can this approach work for other heavy libraries?

Yes. Chat widgets, analytics, maps, and heavy visualization libraries are all good candidates for dynamic import and deferred loading.

W

Webvoid Engineering

Webvoid Technologies

Webvoid Technologies builds enterprise AI, automation, and custom software solutions for ambitious organizations. If this post sparked an idea, let us help you turn it into a working product.