DEV Community

Cover image for Optimizing Web Performance: How Lazy-Loading Spline Assets Took Our Build From 30 to 90 in Lighthouse
Tolulope Abolarin
Tolulope Abolarin

Posted on

Optimizing Web Performance: How Lazy-Loading Spline Assets Took Our Build From 30 to 90 in Lighthouse

When Performance Breaks Before Launch.

We faced a common problem while developing a client site at our design agency recently. Everything looked great, but the site was really slow.

We tested it and found that the initial load time was more than 6 seconds. The Time To Interactive was more than 5 seconds, while the page scored 30/100 when we ran it through Lighthouse. Unfortunately, Lighthouse didn’t tell us what was actually causing it, so it was left to us to figure it out.
We finally found the cause of the problem after digging into DevTools performance traces. The site was loading Spline assets before the user needed them and they were blocking the main thread.

Lazy-loading those assets changed everything and this is what we got:

| Metric | Before | After |
| ----- | ----- | ----- |
| Initial Load Time | 6.5s | 1.2s |
| Time to Interactive | 5.3s | 0.8s |
| Largest Contentful Paint | 5.7s | 0.6s |
| Lighthouse Score | 30 → 90 |  |
Enter fullscreen mode Exit fullscreen mode

The load time went down to 1.2s, TTI down to 0.8s and the Lighthouse score shot up to 90. All these without changing the design or doing any compression hacks.

The load time went down to 1.2s, TTI down to 0.8s and the Lighthouse score shot up to 90. All these without changing the design or doing any compression hacks.

Context: The Build was Visually-Heavy

The project relied on multiple 3D spline embeds to create an immersive interface. Spline is great for this because it renders scalable 3D vector scenes. It’s also lighter than video or traditional 3D assets and allows live interaction. But it comes at the cost of having the runtime and model file load immediately unless you do something about it.

That means:

  • The Spline script executes before the page is interactive

  • The model downloads before the user scrolls to it

  • The browser treats it like a high-priority resource

  • Main thread execution stalls

Which is exactly what we saw in DevTools.

The Problem: Lighthouse Didn’t Flag the Bottleneck

Lighthouse gave us red flags about “render-blocking resources” and “heavy JavaScript execution”, but no mention of Spline directly.

It was difficult to spot because the asset didn’t show as an image or a large file. It came up as JavaScript execution time buried under other events. Only a DevTools Performance trace made it easier to see the problem:

  • Spline script was loaded in <head>

  • Execution started before anything else rendered

  • The main thread was blocked for hundreds of milliseconds

  • All meaningful content waited behind it

The page wasn’t slow because the assets were too large. It was slow because they loaded too early.

The Fix: Lazy-Loading the Spline Elements

We already lazy-load images, so we applied the same logic to Spline. Basically, don’t load it until the user is close to seeing it.

Spline Lazy Loading Pattern

function lazyLoadSpline(container) {`  
  `const observer = new IntersectionObserver(entries => {`  
    `entries.forEach(entry => {`  
      `if (entry.isIntersecting) {`  
        `entry.target.loadSplineAsset();`  
        `observer.unobserve(entry.target);`  
      `}`  
    `});`  
  `});`

  `observer.observe(container);`  
`}
Enter fullscreen mode Exit fullscreen mode

Placeholder Strategy

We used static thumbnail placeholders to stop the layout from shifting. We also used a reserved container height and applied an optional loading state. All these stopped the layout from jumping when the embed initialized.

Why Spline Flies Under the Radar in Audits

Spline assets don’t behave like images, video or fonts, which means they don’t show up under “Large Media” or “Unused JS”. They also don’t trigger obvious Lighthouse warnings. Instead, they work like a hybrid of script execution, asset streaming and GPU rendering.

This means you can only catch the issue by looking at:

  • DevTools Network waterfall

  • Main thread flamegraph

  • CPU/JS execution timeline

Results: Before vs After

| Metric | Before | After |
| ----- | ----- | ----- |
| First Paint | 3.4s | 0.7s |
| LCP | 5.7s | 0.6s |
| TTI | 5.3s | 0.8s |
| Lighthouse | 30 | 90 |
Enter fullscreen mode Exit fullscreen mode

In the end, we didn’t have to modify the Spline assets themselves or reduce resolution. We solved what seemed like a serious problem just by delaying when the Spline assets loaded.

Lessons Learned

What We Learned Why It Matters
Performance issues are often timing-based Not just about file size
Lighthouse is not a full diagnostic tool Always investigate manually
Lightweight assets can still block the main thread Rendering work matters
Heavy visuals should never load before above-the-fold content Prioritization > compression
Lazy loading is a performance technique, not just a UX feature It frees CPU + bandwidth

Practical Checklist for Future Builds

Based on the lessons learnt from the problem, we’ve created a checklist for future builds.

  • Audit runtime-based assets, not just file sizes
  • Treat 3D embeds like video: load only when needed
  • Use IntersectionObserver for scroll-based activation
  • Always test on mid-range real devices, not just desktop throttling
  • Use placeholders to prevent layout shift (CLS)
  • Record a DevTools performance trace before launch
  • Don’t assume Lighthouse tells the whole story

Final Thoughts

Having smaller files isn’t the only thing to aim for if you want a faster website. You also have to make sure the right things load at the right time. Spline is a reliable tool for interactive web experiences, but you need to integrate it with performance in mind. All the site needed to become faster was moving from “load immediately” to “load when needed”. And we didn’t have to sacrifice visuals.

If Lighthouse isn’t showing you the real performance issue, it doesn’t mean there isn’t one. Sometimes you need to open DevTools and follow the execution timeline to find the fix.

Top comments (3)

Collapse
 
aarongibbs profile image
Aaron Gibbs

Really insightful breakdown of how timing, not just asset size, can wreck performance—those before/after numbers are wild. Do you have any recommended resources, talks, or docs on profiling main-thread work for WebGL/3D embeds or on advanced use of DevTools performance tracing that helped shape this approach?

Collapse
 
tolumen profile image
Tolulope Abolarin

Appreciate this, the number change shook me too.

Honestly, a lot of this came from trial and error. I kept moving things and experimenting for a few days until I removed the spline assets and tested it.

Collapse
 
codedzephyr profile image
Salihu Abdulhamid

Agba dev