From 0a14de02693ce81934b39c31c876cbb38f3f0afe Mon Sep 17 00:00:00 2001 From: Mike Karl Date: Wed, 22 Apr 2026 20:27:52 +0200 Subject: [PATCH] subtitle flipper --- src/data/site.ts | 7 +++- src/sections/HeroSection.tsx | 69 ++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/data/site.ts b/src/data/site.ts index a7b75c1..8133f4c 100644 --- a/src/data/site.ts +++ b/src/data/site.ts @@ -27,7 +27,12 @@ export const footerContent = { }; export const heroContent = { - subtitle: "Systementwickler", + subtitle: [ + "Systementwickler", + "Creative Technologist", + "Low-Level Enthusiast", + "Graphics Programmer", + ], nameFirst: "MIKE", nameLast: "KARL", }; diff --git a/src/sections/HeroSection.tsx b/src/sections/HeroSection.tsx index e9226d2..c5f3f10 100644 --- a/src/sections/HeroSection.tsx +++ b/src/sections/HeroSection.tsx @@ -6,6 +6,8 @@ import { ScrollTrigger } from "gsap/ScrollTrigger"; import ParticleGrid from "../components/ParticleGrid"; import { heroContent, site } from "../data/site"; +const subtitles = heroContent.subtitle; + gsap.registerPlugin(ScrollTrigger); export default function HeroSection() { @@ -80,9 +82,9 @@ export default function HeroSection() { ref={contentRef} className="relative z-10 text-center px-6" > -

- {heroContent.subtitle} -

+
+ +

); } + +function SubtitleFlipper() { + const containerRef = useRef(null); + + useEffect(() => { + const container = containerRef.current; + if (!container) return; + + const items = container.querySelectorAll(".subtitle-item"); + if (items.length <= 1) return; + + gsap.set(items, { yPercent: 100, opacity: 0 }); + gsap.set(items[0], { yPercent: 0, opacity: 1 }); + + let current = 0; + let timeoutId: ReturnType; + const duration = 0.5; + const hold = 2500; + + const showNext = () => { + const next = (current + 1) % items.length; + + gsap.to(items[current], { + yPercent: -100, + opacity: 0, + duration, + ease: "power2.inOut", + }); + + gsap.fromTo( + items[next], + { yPercent: 100, opacity: 0 }, + { yPercent: 0, opacity: 1, duration, ease: "power2.inOut" } + ); + + current = next; + timeoutId = setTimeout(showNext, hold); + }; + + timeoutId = setTimeout(showNext, hold); + + return () => { + clearTimeout(timeoutId); + gsap.killTweensOf(items); + }; + }, []); + + return ( +
+ {subtitles.map((text, i) => ( + + {text} + + ))} +
+ ); +}