/** * CPPN Hero Section Template * * A hero section with a generative CPPN (Compositional Pattern-Producing Network) * shader background. Features GSAP SplitText animations for smooth text reveals. * * Dependencies: * - @react-three/fiber * - @react-three/drei * - gsap (with SplitText plugin) * - three */ 'use client'; import { useRef, useMemo } from 'react'; import { Canvas, useFrame, extend } from '@react-three/fiber'; import { shaderMaterial } from '@react-three/drei'; import * as THREE from 'three'; import { useGSAP } from '@gsap/react'; import gsap from 'gsap'; import { SplitText } from 'gsap/SplitText'; import { vertexShader, fragmentShader } from '../shaders/cppn-generative.glsl'; gsap.registerPlugin(SplitText, useGSAP); // ============================================ // SHADER MATERIAL // ============================================ const CPPNShaderMaterial = shaderMaterial( { iTime: 0, iResolution: new THREE.Vector2(1, 1) }, vertexShader, fragmentShader ); extend({ CPPNShaderMaterial }); // ============================================ // 3D COMPONENTS // ============================================ function ShaderPlane() { const meshRef = useRef(null!); const materialRef = useRef(null!); useFrame((state) => { if (!materialRef.current) return; materialRef.current.iTime = state.clock.elapsedTime; const { width, height } = state.size; materialRef.current.iResolution.set(width, height); }); return ( ); } function ShaderBackground() { const canvasRef = useRef(null); const camera = useMemo(() => ({ position: [0, 0, 1] as [number, number, number], fov: 75, near: 0.1, far: 1000 }), []); useGSAP( () => { if (!canvasRef.current) return; gsap.set(canvasRef.current, { filter: 'blur(20px)', scale: 1.1, autoAlpha: 0.7 }); gsap.to(canvasRef.current, { filter: 'blur(0px)', scale: 1, autoAlpha: 1, duration: 1.5, ease: 'power3.out', delay: 0.3 }); }, { scope: canvasRef } ); return (
); } // ============================================ // HERO COMPONENT // ============================================ interface CPPNHeroProps { title: string; description: string; badgeText?: string; badgeLabel?: string; ctaButtons?: Array<{ text: string; href: string; primary?: boolean }>; microDetails?: Array; } export function CPPNHero({ title, description, badgeText = "Generative Surfaces", badgeLabel = "New", ctaButtons = [ { text: "Get started", href: "#get-started", primary: true }, { text: "View showcase", href: "#showcase" } ], microDetails = ["Low‑weight font", "Tight tracking", "Subtle motion"] }: CPPNHeroProps) { const sectionRef = useRef(null); const headerRef = useRef(null); const paraRef = useRef(null); const ctaRef = useRef(null); const badgeRef = useRef(null); const microRef = useRef(null); const microItem1Ref = useRef(null); const microItem2Ref = useRef(null); const microItem3Ref = useRef(null); useGSAP( () => { if (!headerRef.current) return; document.fonts.ready.then(() => { const split = new SplitText(headerRef.current!, { type: 'lines', wordsClass: 'lines', }); gsap.set(split.lines, { filter: 'blur(16px)', yPercent: 30, autoAlpha: 0, scale: 1.06, transformOrigin: '50% 100%', }); if (badgeRef.current) { gsap.set(badgeRef.current, { autoAlpha: 0, y: -8 }); } if (paraRef.current) { gsap.set(paraRef.current, { autoAlpha: 0, y: 8 }); } if (ctaRef.current) { gsap.set(ctaRef.current, { autoAlpha: 0, y: 8 }); } const microItems = [microItem1Ref.current, microItem2Ref.current, microItem3Ref.current].filter(Boolean); if (microItems.length > 0) { gsap.set(microItems, { autoAlpha: 0, y: 6 }); } const tl = gsap.timeline({ defaults: { ease: 'power3.out' }, }); if (badgeRef.current) { tl.to(badgeRef.current, { autoAlpha: 1, y: 0, duration: 0.5 }, 0.0); } tl.to( split.lines, { filter: 'blur(0px)', yPercent: 0, autoAlpha: 1, scale: 1, duration: 0.9, stagger: 0.15, }, 0.1, ); if (paraRef.current) { tl.to(paraRef.current, { autoAlpha: 1, y: 0, duration: 0.5 }, '-=0.55'); } if (ctaRef.current) { tl.to(ctaRef.current, { autoAlpha: 1, y: 0, duration: 0.5 }, '-=0.35'); } if (microItems.length > 0) { tl.to(microItems, { autoAlpha: 1, y: 0, duration: 0.5, stagger: 0.1 }, '-=0.25'); } }); }, { scope: sectionRef }, ); return (
{/* Badge */}
{badgeLabel} {badgeText}
{/* Title */}

{title}

{/* Description */}

{description}

{/* CTA Buttons */}
{ctaButtons.map((button, index) => ( {button.text} ))}
{/* Micro Details */}
    {microDetails.map((detail, index) => { const refMap = [microItem1Ref, microItem2Ref, microItem3Ref]; return (
  • {detail}
  • ); })}
{/* Bottom gradient fade */}
); } // ============================================ // USAGE EXAMPLE // ============================================ /* import { CPPNHero } from './cppn-hero'; function LandingPage() { return ( ); } */ // ============================================ // TYPE AUGMENTATION // ============================================ declare module '@react-three/fiber' { interface ThreeElements { cPPNShaderMaterial: any; } } export default CPPNHero;