diff --git a/public/img/clouds.png b/public/img/clouds.png deleted file mode 100644 index 528ca99d..00000000 Binary files a/public/img/clouds.png and /dev/null differ diff --git a/public/img/clouds.webp b/public/img/clouds.webp new file mode 100644 index 00000000..a8a10249 Binary files /dev/null and b/public/img/clouds.webp differ diff --git a/public/img/earth-blue-marble.jpg b/public/img/earth-blue-marble.jpg deleted file mode 100644 index e673a7c5..00000000 Binary files a/public/img/earth-blue-marble.jpg and /dev/null differ diff --git a/public/img/earth-blue-marble.webp b/public/img/earth-blue-marble.webp new file mode 100644 index 00000000..39fe98e7 Binary files /dev/null and b/public/img/earth-blue-marble.webp differ diff --git a/src/app/(marketing)/page.tsx b/src/app/(marketing)/page.tsx index ea5b022e..1caecd5a 100644 --- a/src/app/(marketing)/page.tsx +++ b/src/app/(marketing)/page.tsx @@ -43,9 +43,9 @@ export default async function Landing() { return ( <> - {/* Preload globe textures so they're cached before the client component mounts */} - - + {/* ponytail: no texture preload — LiveGlobe is dynamic({ ssr: false }), so it + mounts after hydration anyway. Preloading pulled 6.5MB into the critical + window ahead of the render-blocking CSS that gates first paint. */} diff --git a/src/components/features/globe/LiveGlobe.tsx b/src/components/features/globe/LiveGlobe.tsx index 9cceedfc..762b9cc3 100644 --- a/src/components/features/globe/LiveGlobe.tsx +++ b/src/components/features/globe/LiveGlobe.tsx @@ -160,7 +160,7 @@ export function LiveGlobe({ // Add clouds if (showClouds) { - new TextureLoader().load("/img/clouds.png", (texture) => { + new TextureLoader().load("/img/clouds.webp", (texture) => { if (cancelled || !globe) return; clouds = new Mesh( new SphereGeometry( @@ -168,8 +168,12 @@ export function LiveGlobe({ 75, 75, ), + // ponytail: alphaMap, not map. The old RGBA PNG was white wherever + // alpha > 0 and black elsewhere, so its colour channel carried no + // information the mask doesn't — dropping it let the mask compress + // as plain greyscale (4.8MB -> 922KB) at full 4096x2048. new MeshPhongMaterial({ - map: texture, + alphaMap: texture, transparent: true, opacity: 0.3, }), @@ -533,7 +537,7 @@ export function LiveGlobe({ width={width} height={height} backgroundColor="rgba(0,0,0,0)" - globeImageUrl="/img/earth-blue-marble.jpg" + globeImageUrl="/img/earth-blue-marble.webp" showAtmosphere={false} onGlobeReady={() => { globeReadyRef.current = true;