From 5.9s to 3.8s: Why a Hidden Hero Makes Everything Slow
A Through Tenon teardown: Lighthouse mobile 75 with a 5.9s LCP caused by an entrance animation, and the fixes that recovered two seconds.
Answer in 30 seconds
Lighthouse mobile went 75 (LCP 5.9s) to 88 (LCP 3.8s) after the hero stopped waiting on a client-side entrance animation and became server-rendered HTML that paints immediately, plus removal of a 1.78 MB image URL that was preloaded but never displayed. Animation moved into small client islands that enhance the page instead of gating it.
Through Tenon is another self-initiated concept build (a furniture storefront, no client affiliation implied) and its teardown teaches the opposite lesson to the 768 KB preload story: there, one import downloaded junk. Here, the page was fast but hid itself.
Starting score: 75 · LCP 5.9s (Lighthouse mobile, median of three runs). Ending score: 88 · LCP 3.8s. Later, on a measured 16ms connection: 100 · LCP 1.0s.
The Symptom: A Blank Page That Was Fully Downloaded
The confusing part of this bug is the waterfall. The HTML arrived quickly. The image was small, modern format, right-sized. Every individual asset looked fine. And yet the hero: the largest text block on the page: did not paint for nearly six seconds on Lighthouse's mobile profile.
The answer was in the first line of the hero component:
<motion.div initial="hidden" animate="visible">
A clip-path entrance animation. The server sent the hero inside a container whose initial state is visibility-hidden. For it to become visible, the animation library had to download, hydrate, and start the animation on the client.
So the "painting" of the hero depended on: JS chunk download → hydration → animation frame 1. On a throttled phone connection, that chain is thousands of milliseconds. Until it completed, the page was contentless: not because the bytes were slow, but because the CSS said "not yet".
Finding 2: A 1.78 MB Image That Was Preloaded and Never Used
Same class of bug as the 768 KB preload in the sister teardown, different file: a hero image URL, 1.78 MB from an image CDN, sat in a preload tag from an earlier design iteration. The browser fetched it at high priority on every visit, even though nothing on the page referenced it.
Deleting the preload did not change the layout by a pixel. It changed the queue. And the queue is what LCP measures.
The Two Structural Fixes
1. The hero became a server component that paints at full opacity. The entrance animation was not deleted: it was relocated. The hero's content now arrives as plain HTML and is visible on first paint, and the ambient motion (a slow parallax on decorative layers) moved into small client islands below it. The visitor gets content at first byte; the motion decorates it a moment later.
That sentence is the rule this whole class of bugs breaks: animation should decorate content, never gate it. If your CSS says "hidden" and your JavaScript says "visible", then your JavaScript is your renderer, and the visitor pays for every byte of it.
2. Every critical element got explicit dimensions. Grid items, hero, and the product card image all carry width/height. The browser can lay out the entire above-the-fold region from HTML alone, before any image lands.
Result: 88 · LCP 3.8s, a 2.1s improvement, with no change to the visual design. Later work on the image pipeline and the variant switcher took it to 95 · LCP 3.0s on the Lighthouse preset, and 100 · LCP 1.0s on the measured connection.
The General Rule, Now With Evidence Twice Over
Two builds. Two very different symptoms (one downloading a phantom asset, one hiding its content behind JavaScript) and both were single-line-to-three-line fixes in an otherwise healthy codebase. Speed work rarely starts with a rewrite. It starts with reading the network waterfall and the first screen's DOM.
The order I check, every time:
- What loads before first paint that isn't needed? (preloads, unused fonts, phantom images)
- What paints late because JavaScript said so? (initial-state animations, client-rendered heroes, auth-gated content)
- What is served 2–3× larger than it displays? (images, fonts)
The dates, profiles and both build breakdowns are public: Small Batch Brine and Through Tenon. If you would rather have the audit than read about it, the free grader takes 30 seconds, and a speed quick fix starts at $100 with the before/after written down.
Work with me
Need a site that loads fast and sells?
Seven live builds with dated measurements and fixed prices published up front. Read the breakdowns: or send me the rough version of your problem.
Related reads
How a 768 KB Preload Made a Storefront Take 7.2s to Paint
A Small Batch Brine teardown: Lighthouse mobile 74 with a 7.2s LCP, one root cause, and the fixes that took it to 97 (LCP 2.0s). Dated and reproducible.
Your performance score is a sales number, not a report card
Core Web Vitals, why Google penalizes slow websites, and the engineering behind a near-perfect Lighthouse score.
What one churned customer actually costs you
A SaaS ROI method for founders who think in MRR, churn and onboarding conversion. Compare one lost customer to the cost of fixing the leak.