Skip to content

perf(landing): below-fold render + LCP/CLS/compositing hardening#271

Merged
ignromanov merged 10 commits into
developfrom
056-landing-scroll-perf
May 28, 2026
Merged

perf(landing): below-fold render + LCP/CLS/compositing hardening#271
ignromanov merged 10 commits into
developfrom
056-landing-scroll-perf

Conversation

@ignromanov
Copy link
Copy Markdown
Owner

@ignromanov ignromanov commented May 28, 2026

Summary

Landing-page performance hardening across load, render, Core Web Vitals, and mobile compositing. Started as a below-fold render-cost pass (FAQ + ComparisonTable), expanded after a 4-dimension perf audit (bundle / render / web-vitals / paint) into a focused, low-risk batch. All landing-scoped; one global tweak (NetworkBackground) called out below.

Changes

Below-fold render cost (original)

  • FAQ memoization — hoist useReducedMotion to one parent call, React.memo FaqItem, useCallback handlers
  • Remove backdrop-blur-sm from ComparisonTable section root — kills a full-screen blur pass
  • Decouple ComparisonTable via children-prop from LandingContent → smaller re-render scope on scroll

LCP / load

  • HeroSection → Server Component — CTA extracted to a thin HeroCta client child; the <h1> now paints from SSR HTML without waiting for hydration
  • JSON-LD via plain <script> (RSC) instead of next/script — structured data lands in initial HTML (crawler-safe) + removes 4 hydration registrations
  • optimizePackageImports += framer-motion, @web3icons/react

CLS / paint / compositing (mobile)

  • NetworkBackground blur-3xlblur-2xl + will-change-transform + transition guarded under prefers-reduced-motionglobal (background on all pages); visually equivalent at 10% opacity, snapshot updated
  • Strip backdrop-blur-sm from below-fold section roots + nested FAQ double-blur + cards (SocialProofStrip, HowItWorks, FaqSection, WhyVoidPay cards, AudienceCard) — replaced with solid translucent bg
  • Below-fold placeholder reserves correct heightBelowFoldPlaceholder passed as skeleton prop (consistent min-h-[300vh] pre/post-trigger), eliminating CLS on the skeleton→content swap

Runtime / render

  • Demo rotation pauses on visibilitychange — no interval ticks / heavy InvoicePaper re-renders while tab is hidden
  • Remove mount-time setNetworkTheme('ethereum') — store default is already ethereum; drops a redundant repaint in the LCP window
  • memo + hoistReact.memo on AudienceCard / HeroFeatureCard / TimelineStep; hoist topCards (static derivation) to module scope

Test plan

  • type-check:build — 0 errors
  • lint — 0 errors
  • Unit/snapshot tests — 216 passed / 1 skipped (landing + network-background); snapshots updated for blur changes
  • Manual visual review — hero, NetworkBackground glow, below-fold sections after blur removal, scroll smoothness (confirmed good)
  • FAQ expand/collapse + ComparisonTable hover/expand interactions intact

Notes

  • Video poster/asset perf (VideoSection, 945 KB poster, 10 MB mp4s) is out of scope here — it lives on the video branch; captured separately as a handoff.
  • React Compiler global adoption tracked in GH#212 (not in this PR).

…n FaqItem (1-3/4)

Kai lag-analysis 2026-05-25: 12 matchMedia subscriptions (one per FaqItem)
collapsed to 1 in FaqSection. FaqItem wrapped in React.memo; handleToggle
stabilised via useCallback + index passed as arg to avoid per-render arrow
wrappers. backdrop-blur-sm removed from section root (Fix 2, FAQ part).
…oot (2/4)

Kai lag-analysis 2026-05-25: backdrop-blur-sm on section roots forces GPU
compositing layers during scroll. Inner accordion card retains backdrop-blur-sm
(visually load-bearing). Section root is now flat bg.
…pattern (4/4)

Kai lag-analysis 2026-05-25: ComparisonTable has no hooks/state/handlers and
does not need to be bundled inside BelowFoldSections client chunk. Moved to
comparisonTable: ReactNode prop; LandingContent passes <ComparisonTable />.
Full RSC gain requires LandingContent server-shell split (follow-up for Kai).
@vercel
Copy link
Copy Markdown

vercel Bot commented May 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
voidpay Ready Ready Preview, Comment May 28, 2026 7:29pm

…Server Component

<h1> now paints from SSR HTML without waiting for hydration.
HeroCta owns the track() onClick call as a thin 'use client' boundary.
…m, guard transition under reduced-motion

Reduces compositing cost on mobile. motion-reduce:transition-none prevents
color-transition animation for users who opted out. Test updated to match blur-2xl.
…nd cards

Removes 4px blur layers that trigger GPU compositing on mobile with no visible
effect on zinc-950 bg. Replaced with solid semi-opaque bg tokens. Affected:
SocialProofStrip, HowItWorks, FaqSection (section + inner accordion), WhyVoidPay
cards (×3), AudienceCard. ComparisonTable already done (cc2dc46). Snapshots updated.
Stops the 10s interval while the tab is backgrounded so it stops re-rendering
the InvoicePaper subtree when the user is not watching. Composes independently
with the existing manual pause/resume and hover-pause — visibility state is a
separate isHidden flag, not overwriting isPaused. Tests: TDD red→green verified.
…default already 'ethereum'

uiSlice.ts initializes networkTheme: 'ethereum'. The useEffect mutation on mount
was redundant. All other pages (create, pay, invoice) set their own theme explicitly
from networkId — landing's removal is safe. Also consolidates below-fold placeholder
to pass BelowFoldPlaceholder as skeleton prop (single consistent placeholder with
min-h-[300vh] both pre- and post-trigger, eliminating CLS on the swap).
@ignromanov ignromanov changed the title perf(landing): reduce below-fold render cost (FAQ memo + ComparisonTable decouple) perf(landing): below-fold render + LCP/CLS/compositing hardening May 28, 2026
@ignromanov ignromanov merged commit 2b1b703 into develop May 28, 2026
7 checks passed
@ignromanov ignromanov deleted the 056-landing-scroll-perf branch May 28, 2026 19:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant