// Utility Functions function fadeFromBottom( selector, offset = 40, duration = 1, delay = 0, ease = "power2.out" ) { gsap.from(selector, { scrollTrigger: { trigger: selector, start: "top 80%" }, opacity: 0, y: offset, duration, delay, ease, }); } function staggerChildren( triggerSelector, childSelector, y = 30, stagger = 0.2 ) { gsap.from(childSelector, { scrollTrigger: { trigger: triggerSelector, start: "top 75%" }, opacity: 0, y, duration: 0.6, ease: "power2.out", stagger, }); } function initAnimations() { gsap.set(".page-wrapper", { visibility: "visible" }); const tlHero = gsap.timeline(); // Step 1: hero_section sichtbar machen (gegen FOUC) tlHero.to(".hero_section", { opacity: 1, duration: 0.01, // sofort sichtbar }); // Step 2: Bild rein mit Blur + Scale tlHero.fromTo( ".hero_img", { opacity: 0, y: 50, scale: 0.975, filter: "blur(6px)", }, { opacity: 1, y: 0, scale: 1, filter: "blur(0px)", duration: 1.2, ease: "power2.out", } ); // Step 3: Content ganz normal einblenden tlHero.fromTo( ".hero_content_wrap", { opacity: 0, y: 30, }, { opacity: 1, y: 0, duration: 1, ease: "power2.out", }, "-=1" // etwas früher, parallel zur Bildanimation ); // Services fadeFromBottom(".services_overview_heading", 50, 1.2); staggerChildren(".service_wrapper", ".service_wrapper", 60, 0.2); // Map Section const split = new SplitText(".benefits-subheading", { type: "words" }); const tlMap = gsap.timeline({ scrollTrigger: { trigger: ".benefits_heading", start: "top 75%", }, }); tlMap .from(".benefits_heading", { y: 40, opacity: 0, duration: 1, ease: "power2.out", }) .from( split.words, { opacity: 0, y: 10, duration: 0.6, ease: "power1.out", stagger: 0.015, }, "-=0.6" ) .from( ".benefits_map_contain", { opacity: 0, y: 20, duration: 0.6, ease: "power1.out", }, "-=0.4" ) .from( ".map_dot", { scale: 0, opacity: 0, duration: 0.4, ease: "back.out(1.7)", stagger: 0.1, }, "-=0.2" ); // Benefits 2 const tlBenefits2 = gsap.timeline({ scrollTrigger: { trigger: ".benefits-2-heading", start: "top 75%" }, }); tlBenefits2.from(".benefits-2-heading", { y: 40, opacity: 0, duration: 0.5, ease: "power2.out", }); document.querySelectorAll(".benefits_2_item").forEach((item) => { const number = item.querySelector(".benefits_2_numbering"); const heading = item.querySelector(".benefits_2_heading"); const description = item.querySelector(".benefits_2_description_wrap"); const line = item.querySelector('[class*="benefits_item_line"]'); gsap.set(line, { transformOrigin: "left center", scaleX: 0, opacity: 0 }); tlBenefits2 .from( [number, heading, description], { opacity: 0, x: -15, duration: 0.3, ease: "power1.out", stagger: 0.05, }, "-=0.4" ) .to( line, { scaleX: 1, opacity: 1, duration: 0.3, ease: "power2.out", }, "-=0.2" ); }); tlBenefits2.from( ".benefits_2_image_wrapper", { y: 30, opacity: 0, duration: 0.4, ease: "power1.out", }, "-=0.4" ); // Process Tabs const tlProcessTabs = gsap.timeline({ scrollTrigger: { trigger: ".process-tabs-heading", start: "top 75%" }, }); tlProcessTabs .from(".process-tabs-heading", { opacity: 0, y: 40, duration: 1, ease: "power2.out", }) .from( ".process-tabs_wrap", { opacity: 0, y: 30, duration: 0.6, ease: "power2.out" }, "-=0.6" ) .from( ".process-tab", { opacity: 0, y: 20, duration: 0.4, ease: "power1.out", stagger: 0.1 }, "-=0.4" ); const subSplit = new SplitText(".process-tabs-p", { type: "words" }); tlProcessTabs.from( subSplit.words, { opacity: 0, y: 10, duration: 0.5, ease: "power1.out", stagger: 0.05, }, "-=0.3" ); // Swiper const tlProjects = gsap.timeline({ scrollTrigger: { trigger: ".projects-section", start: "top 75%" }, }); tlProjects .from(".projects-heading", { y: 40, opacity: 0, duration: 1, ease: "power2.out", }) .from( [".custom-prev", ".custom-next"], { scale: 0, opacity: 0, duration: 0.4, ease: "back.out(1.7)", stagger: 0.1, }, "-=0.4" ) .from( ".swiper-bullet", { scale: 0, opacity: 0, duration: 0.2, ease: "back.out(1.7)", stagger: 0.05, }, "-=0.3" ) .from(".swiper-wrapper.is-home", { opacity: 0, y: 10, duration: 0.4, ease: "back.out(1.7)", }); // Product Section fadeFromBottom(".products-description_heading", 50, 0.8); fadeFromBottom(".products-description_subheading", 40, 0.8, 0.2); gsap.from(".products-description_stat, .products-description-stat-p", { scrollTrigger: { trigger: ".products-overview_section", start: "top 80%", }, y: 30, opacity: 0, duration: 0.6, delay: 0.4, stagger: 0.1, ease: "power2.out", }); gsap.fromTo( ".product-overview_img", { yPercent: -5, opacity: 0 }, { scrollTrigger: { trigger: ".products-overview_section", start: "top 80%", }, opacity: 1, duration: 1, ease: "power2.out", onComplete: () => { gsap.to(".product-overview_img", { yPercent: -10, duration: 2, ease: "sine.inOut", yoyo: true, repeat: -1, }); }, } ); // Testimonials fadeFromBottom(".testimonial1-heading"); staggerChildren(".testimonial1-section", ".testimonial-wrapper"); // CTA 1 fadeFromBottom(".cta1-contain"); // FAQ fadeFromBottom(".faq-heading"); staggerChildren(".faq-section", ".faq-item", 30, 0.15); // Final CTA const tlSolarCTA = gsap.timeline({ scrollTrigger: { trigger: ".sec-cta_section", start: "top 75%", }, }); tlSolarCTA.from(".sec-cta_img_wrap", { x: -50, opacity: 0, scale: 0.97, duration: 1, ease: "power2.out", }); tlSolarCTA.from( ".sec-cta_header_wrap", { y: 40, opacity: 0, duration: 1, ease: "power2.out", }, "-=0.7" ); // === About Page: Hero === if (document.querySelector(".about-hero_section")) { const tlAboutHero = gsap.timeline({ scrollTrigger: { trigger: ".about-hero_section", start: "top 60%", }, }); tlAboutHero .fromTo( ".about-hero_headline", { opacity: 0, y: 40 }, { opacity: 1, y: 0, duration: 1, ease: "power2.out", } ) .fromTo( ".about-hero_subheadline", { opacity: 0, y: 20 }, { opacity: 1, y: 0, duration: 0.8, ease: "power2.out", }, "-=0.6" ); } // === About Page: Intro Section === if (document.querySelector(".about-intro_section")) { const tlIntro = gsap.timeline({ scrollTrigger: { trigger: ".about-intro_section", start: "top 60%", }, }); tlIntro .fromTo( ".about-intro_image_wrapper", { x: -50, opacity: 0 }, { x: 0, opacity: 1, duration: 1, ease: "power2.out", } ) .fromTo( ".about-intro_header_wrap", { y: 40, opacity: 0 }, { y: 0, opacity: 1, duration: 0.8, ease: "power2.out", }, "-=0.6" ); } // === About Page: Services Section === if (document.querySelector(".services-section2_heading")) { const tlServices2 = gsap.timeline({ scrollTrigger: { trigger: ".services-section2_heading", start: "top 60%", }, }); // Heading animation tlServices2.fromTo( ".services-section2_heading", { opacity: 0, y: 40, }, { opacity: 1, y: 0, duration: 1, ease: "power2.out", } ); // Items animation with stagger tlServices2.fromTo( ".services-service-item", { opacity: 0, y: 30, }, { opacity: 1, y: 0, duration: 0.6, ease: "power2.out", stagger: 0.2, }, "-=0.5" ); } if (document.querySelector(".references2_section")) { const tlRefs = gsap.timeline({ scrollTrigger: { trigger: ".references2_section", start: "top 60%", }, }); // Überschrift tlRefs.fromTo( ".references2_heading", { y: 40, opacity: 0 }, { y: 0, opacity: 1, duration: 1, ease: "power2.out", } ); // Grid-Items (gestaffelt) tlRefs.fromTo( ".references2_ref_item", { y: 30, opacity: 0 }, { y: 0, opacity: 1, duration: 0.6, ease: "power2.out", stagger: 0.15, }, "-=0.6" ); } if (document.querySelector(".team_section")) { const tlTeam = gsap.timeline({ scrollTrigger: { trigger: ".team_section", start: "top 60%", }, }); // Heading tlTeam.fromTo( ".team_heading", { y: 40, opacity: 0 }, { y: 0, opacity: 1, duration: 1, ease: "power2.out", } ); // Member gestaffelt tlTeam.fromTo( ".team_member_wrap", { y: 30, opacity: 0 }, { y: 0, opacity: 1, duration: 0.6, ease: "power2.out", stagger: 0.15, }, "-=0.5" ); } // === Services Hero Section === if (document.querySelector(".services_hero_section")) { const tlServicesHero = gsap.timeline(); // === Bild: sanftes Fade-In mit leichtem Slide von unten === tlServicesHero.fromTo( ".services_hero_img", { opacity: 0, y: 20, }, { opacity: 1, y: 0, duration: 0.4, ease: "power2.out", } ); // === Headline & Paragraph: clean stagger, präzise Bewegung === tlServicesHero.fromTo( [".services_hero_heading", ".services_hero_p"], { opacity: 0, y: 15, }, { opacity: 1, y: 0, duration: 0.45, ease: "power2.out", stagger: 0.06, }, "-=0.25" ); // === Subheading & Button: leicht verzögert, minimal slide === tlServicesHero.fromTo( [".services_hero_subheading", ".btn_main_wrap.services_section"], { opacity: 0, y: 10, }, { opacity: 1, y: 0, duration: 0.4, ease: "power2.out", stagger: 0.08, }, "-=0.3" ); } gsap.utils.toArray(".installation-section").forEach((section) => { const tl = gsap.timeline({ scrollTrigger: { trigger: section, start: "top 70%", }, }); tl.fromTo( section.querySelector(".installation-img"), { opacity: 0, y: 20 }, { opacity: 1, y: 0, duration: 0.4, ease: "power2.out" } ) .fromTo( section.querySelector(".installation-heading"), { opacity: 0, y: 15 }, { opacity: 1, y: 0, duration: 0.4, ease: "power2.out" }, "-=0.3" ) .fromTo( section.querySelector(".installation-paragraph"), { opacity: 0, y: 10 }, { opacity: 1, y: 0, duration: 0.4, ease: "power2.out" }, "-=0.3" ) .fromTo( section.querySelectorAll(".highlight-item-paragraph"), { opacity: 0, y: 10 }, { opacity: 1, y: 0, duration: 0.35, stagger: 0.1, ease: "power2.out", }, "-=0.2" ); }); gsap.registerPlugin(ScrollTrigger, SplitText); if (document.querySelector(".maintenance_heading")) { const tlMaintenance = gsap.timeline({ scrollTrigger: { trigger: ".maintenance_section", start: "top 70%", }, }); // === Heading tlMaintenance.fromTo( ".maintenance_heading", { opacity: 0 }, { opacity: 1, duration: 0.4, ease: "power1.out" } ); // === Typewriter-Effekt (clean, keine Y-Bewegung) const infoElements = gsap.utils.toArray( ".maintenance_info_title, .maintenance_info_text" ); infoElements.forEach((el, i) => { const split = new SplitText(el, { type: "words" }); tlMaintenance.fromTo( split.words, { opacity: 0 }, { opacity: 1, ease: "none", // no bounce, no easing – just like typewriter duration: 0.3, stagger: 0.05, }, "-=0.2" ); }); // === Image rein (schnell, clean) tlMaintenance.fromTo( ".maintenance_img", { opacity: 0 }, { opacity: 1, duration: 0.4, ease: "power1.out", }, "-=0.1" ); } const tlProjectsSwiper2 = gsap.timeline({ scrollTrigger: { trigger: ".references-overview_section", start: "top 75%", }, }); // Heading tlProjectsSwiper2.fromTo( ".references-overview_section", { y: 40, opacity: 0 }, { y: 0, opacity: 1, duration: 0.6, ease: "power2.out" } ); const tlTestimonial = gsap.timeline({ scrollTrigger: { trigger: ".reference_testimonial_section", start: "top 75%", }, }); // Bild tlTestimonial.fromTo( ".reference_testimonial_img", { opacity: 0, y: 30 }, { opacity: 1, y: 0, duration: 0.5, ease: "power2.out" } ); // Name & Sterne Wrapper tlTestimonial.fromTo( ".reference_testimonial_name_wrap", { opacity: 0, y: 30 }, { opacity: 1, y: 0, duration: 0.5, ease: "power2.out" }, "-=0.4" // leicht überlappend mit Bild ); // Sterne gestaffelt tlTestimonial.fromTo( ".testimonial1-star-rating path", { opacity: 0, y: 10 }, { opacity: 1, y: 0, duration: 0.3, ease: "power2.out", stagger: 0.1, // einzeln rein }, "-=0.4" ); // Text tlTestimonial.fromTo( ".reference_testimonial_p", { opacity: 0, y: 30 }, { opacity: 1, y: 0, duration: 0.6, ease: "power2.out" }, "-=0.3" ); } document.fonts.ready.then(initAnimations);