perf: remove WebGL ShaderGradient and reduce BackgroundBlobs blur
Some checks failed
Gitea CI / test-build (push) Successful in 12m1s
Production Deployment (Zero Downtime) / deploy-production (push) Has been cancelled

ShaderGradientBackground used 3 full-screen Three.js WebGL canvases
with a blur(150px) CSS filter, crashing Lighthouse and causing severe
lag in Chrome. BackgroundBlobs also had 7 elements with blur(100-120px)
and per-frame mouse spring tracking compounding the issue.

- Remove ShaderGradientBackground from layout (WebGL not needed for a blur effect)
- Reduce BackgroundBlobs blur from 100-120px to 60px
- Remove mouse tracking spring animations from BackgroundBlobs
- Reduce to 4 blobs (remove 3 least visible)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 01:54:48 +01:00
parent ef72f5fc58
commit c9cd2d734d
2 changed files with 13 additions and 139 deletions

View File

@@ -3,7 +3,6 @@ import { Metadata } from "next";
import { Inter, Playfair_Display } from "next/font/google"; import { Inter, Playfair_Display } from "next/font/google";
import React from "react"; import React from "react";
import ClientProviders from "./components/ClientProviders"; import ClientProviders from "./components/ClientProviders";
import ShaderGradientBackgroundClient from "./components/ShaderGradientBackgroundClient";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { getBaseUrl } from "@/lib/seo"; import { getBaseUrl } from "@/lib/seo";
@@ -36,7 +35,6 @@ export default async function RootLayout({
</head> </head>
<body className={`${inter.variable} ${playfair.variable}`} suppressHydrationWarning> <body className={`${inter.variable} ${playfair.variable}`} suppressHydrationWarning>
<div className="grain-overlay" aria-hidden="true" /> <div className="grain-overlay" aria-hidden="true" />
<ShaderGradientBackgroundClient />
<ClientProviders>{children}</ClientProviders> <ClientProviders>{children}</ClientProviders>
</body> </body>
</html> </html>

View File

@@ -1,169 +1,45 @@
"use client"; "use client";
import { motion, useMotionValue, useTransform, useSpring } from "framer-motion"; import { motion } from "framer-motion";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
const BackgroundBlobs = () => { const BackgroundBlobs = () => {
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);
const springConfig = { damping: 50, stiffness: 50, mass: 2 };
const springX = useSpring(mouseX, springConfig);
const springY = useSpring(mouseY, springConfig);
// Very subtle parallax offsets
const x1 = useTransform(springX, (value) => value / 30);
const y1 = useTransform(springY, (value) => value / 30);
const x2 = useTransform(springX, (value) => value / -25);
const y2 = useTransform(springY, (value) => value / -25);
const x3 = useTransform(springX, (value) => value / 20);
const y3 = useTransform(springY, (value) => value / 20);
const x4 = useTransform(springX, (value) => value / -35);
const y4 = useTransform(springY, (value) => value / -35);
const x5 = useTransform(springX, (value) => value / 15);
const y5 = useTransform(springY, (value) => value / 15);
// Prevent hydration mismatch
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
useEffect(() => { useEffect(() => {
setMounted(true); setMounted(true);
}, []); }, []);
useEffect(() => {
if (!mounted) return;
const handleMouseMove = (e: MouseEvent) => {
const x = e.clientX - window.innerWidth / 2;
const y = e.clientY - window.innerHeight / 2;
mouseX.set(x);
mouseY.set(y);
};
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, [mouseX, mouseY, mounted]);
if (!mounted) return null; if (!mounted) return null;
return ( return (
<div className="fixed inset-0 overflow-hidden pointer-events-none z-0"> <div className="fixed inset-0 overflow-hidden pointer-events-none z-0">
{/* Mint blob - top left */} {/* Mint blob - top left */}
<motion.div <motion.div
className="absolute top-[-10%] left-[-10%] w-[40vw] h-[40vw] bg-liquid-mint/40 rounded-full blur-[100px] mix-blend-multiply" className="absolute top-[-10%] left-[-10%] w-[40vw] h-[40vw] bg-liquid-mint/40 rounded-full blur-[60px] mix-blend-multiply"
style={{ x: x1, y: y1 }} animate={{ scale: [1, 1.15, 1] }}
animate={{ transition={{ duration: 40, repeat: Infinity, ease: "easeInOut", repeatType: "reverse" }}
scale: [1, 1.15, 1],
rotate: [0, 45, 0],
}}
transition={{
duration: 40,
repeat: Infinity,
ease: "easeInOut",
repeatType: "reverse",
}}
/> />
{/* Lavender blob - top right */} {/* Lavender blob - top right */}
<motion.div <motion.div
className="absolute top-[10%] right-[-5%] w-[35vw] h-[35vw] bg-liquid-lavender/35 rounded-full blur-[100px] mix-blend-multiply" className="absolute top-[10%] right-[-5%] w-[35vw] h-[35vw] bg-liquid-lavender/35 rounded-full blur-[60px] mix-blend-multiply"
style={{ x: x2, y: y2 }} animate={{ scale: [1, 1.1, 1] }}
animate={{ transition={{ duration: 45, repeat: Infinity, ease: "easeInOut", repeatType: "reverse" }}
scale: [1, 1.1, 1],
rotate: [0, -30, 0],
}}
transition={{
duration: 45,
repeat: Infinity,
ease: "easeInOut",
repeatType: "reverse",
}}
/> />
{/* Rose blob - bottom left */} {/* Rose blob - bottom left */}
<motion.div <motion.div
className="absolute bottom-[-5%] left-[15%] w-[45vw] h-[45vw] bg-liquid-rose/35 rounded-full blur-[100px] mix-blend-multiply" className="absolute bottom-[-5%] left-[15%] w-[45vw] h-[45vw] bg-liquid-rose/35 rounded-full blur-[60px] mix-blend-multiply"
style={{ x: x3, y: y3 }} animate={{ scale: [1, 1.2, 1] }}
animate={{ transition={{ duration: 50, repeat: Infinity, ease: "easeInOut", repeatType: "reverse" }}
scale: [1, 1.2, 1],
rotate: [0, 60, 0],
}}
transition={{
duration: 50,
repeat: Infinity,
ease: "easeInOut",
repeatType: "reverse",
}}
/> />
{/* Peach blob - middle right */} {/* Peach blob - middle right */}
<motion.div <motion.div
className="absolute top-[40%] right-[10%] w-[30vw] h-[30vw] bg-orange-200/30 rounded-full blur-[120px] mix-blend-multiply" className="absolute top-[40%] right-[10%] w-[30vw] h-[30vw] bg-orange-200/30 rounded-full blur-[60px] mix-blend-multiply"
style={{ x: x4, y: y4 }} animate={{ scale: [1, 1.25, 1] }}
animate={{ transition={{ duration: 55, repeat: Infinity, ease: "easeInOut", repeatType: "reverse" }}
scale: [1, 1.25, 1],
rotate: [0, -45, 0],
}}
transition={{
duration: 55,
repeat: Infinity,
ease: "easeInOut",
repeatType: "reverse",
}}
/>
{/* Blue blob - center */}
<motion.div
className="absolute top-[50%] left-[40%] w-[38vw] h-[38vw] bg-blue-200/30 rounded-full blur-[110px] mix-blend-multiply"
style={{ x: x5, y: y5 }}
animate={{
scale: [1, 1.18, 1],
rotate: [0, 90, 0],
}}
transition={{
duration: 48,
repeat: Infinity,
ease: "easeInOut",
repeatType: "reverse",
}}
/>
{/* Pink blob - bottom right */}
<motion.div
className="absolute bottom-[10%] right-[-8%] w-[32vw] h-[32vw] bg-pink-200/35 rounded-full blur-[100px] mix-blend-multiply"
animate={{
scale: [1, 1.12, 1],
rotate: [0, -60, 0],
x: [0, -20, 0],
y: [0, 20, 0],
}}
transition={{
duration: 43,
repeat: Infinity,
ease: "easeInOut",
repeatType: "reverse",
}}
/>
{/* Yellow-green blob - top center */}
<motion.div
className="absolute top-[5%] left-[45%] w-[28vw] h-[28vw] bg-lime-200/30 rounded-full blur-[115px] mix-blend-multiply"
animate={{
scale: [1, 1.22, 1],
rotate: [0, 75, 0],
x: [0, 15, 0],
y: [0, -15, 0],
}}
transition={{
duration: 52,
repeat: Infinity,
ease: "easeInOut",
repeatType: "reverse",
}}
/> />
</div> </div>
); );