What the 38 Was Telling Me

The biggest offenders were unoptimised images (I was serving full-resolution PNGs where WebP thumbnails should have been), render-blocking scripts, and a 3D Three.js scene loading on the main thread without any code splitting. Each of those three issues alone would have been enough to fail a performance audit.

The Largest Contentful Paint was 5.8 seconds — almost entirely because the hero image was a 4MB JPEG. The browser was spending the first five seconds of the user's visit downloading a picture. Everything else was waiting behind that.

The Fixes That Moved the Score

Next.js Image component with proper width/height and priority on the LCP image. That alone cut the LCP by 3 seconds. Dynamic imports with React.lazy for the Three.js component — it now loads after the initial paint, not before. And moving all analytics scripts to load lazily with next/script strategy='lazyOnload'.

After those three changes: score went from 38 to 91. The three-second load became sub-second on a good connection. The lesson wasn't 'performance is hard' — it was 'I had been ignoring obvious things.'

Key takeaways

  • Run Lighthouse before you share anything publicly — a score under 50 is a red flag that will hurt SEO rankings and first impressions
  • The LCP image (usually your hero) is the single highest-leverage performance fix — serve it as WebP, give it a 'priority' prop in Next.js Image, and specify exact dimensions
  • Lazy-load heavy third-party scripts (analytics, chat widgets) and large JS modules (Three.js, chart libraries) with dynamic imports to keep the initial bundle lean

Conclusion

Performance is a feature. A slow portfolio tells every visitor — including recruiters and potential clients — that you don't pay attention to fundamentals. The fixes are rarely hard once you know what Lighthouse is actually measuring.

Enjoyed this article?

Vivek Kumar Singh

Vivek Kumar Singh

Technical Expert · Full Stack Cloud Engineer · Tokyo, Japan