You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

138 lines
4.8 KiB

import { useEffect, useRef } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
function MainVisual() {
const sectionRef = useRef(null);
const bgRef = useRef(null);
const hero2Ref = useRef(null);
const videoRef = useRef(null);
const text1Ref = useRef(null);
const text2Ref = useRef(null);
const progressBarRef = useRef(null);
useEffect(() => {
const ctx = gsap.context(() => {
const videoEl = videoRef.current;
if (videoEl) {
videoEl.pause();
videoEl.currentTime = 0;
}
gsap.set(hero2Ref.current, { opacity: 0, scale: 1.12, filter: "blur(12px)" });
gsap.set(text2Ref.current, {
opacity: 0,
y: 54,
x: 0,
scale: 0.965,
filter: "blur(10px)",
});
gsap.set(progressBarRef.current, { width: "0%" });
gsap.set(".fill-line", { backgroundPosition: "100% 0%" });
const darkHeroTrigger = ScrollTrigger.create({
trigger: sectionRef.current,
start: "top top",
end: "+=3000",
onEnter: () => document.body.classList.add("is-dark-hero"),
onEnterBack: () => document.body.classList.add("is-dark-hero"),
onLeave: () => document.body.classList.remove("is-dark-hero"),
onLeaveBack: () => document.body.classList.remove("is-dark-hero"),
});
let hero2Started = false;
const tl = gsap.timeline({
scrollTrigger: {
trigger: sectionRef.current,
start: "top top",
end: "+=3000",
scrub: 1.15,
pin: true,
anticipatePin: 1,
onUpdate: (self) => {
gsap.set(progressBarRef.current, { width: `${self.progress * 100}%` });
if (!videoEl) return;
if (self.progress >= 0.42 && !hero2Started) {
hero2Started = true;
videoEl.currentTime = 0;
videoEl.play().catch(() => {});
}
if (self.progress < 0.42 && hero2Started) {
hero2Started = false;
videoEl.pause();
videoEl.currentTime = 0;
}
},
},
});
tl.to(bgRef.current, { width: "100vw", height: "100vh", borderRadius: 0, ease: "none" }, 0).to(bgRef.current, { scale: 1.08, ease: "none" }, 0).to(".fill-line", { backgroundPosition: "0% 0%", ease: "none", stagger: 0.14, duration: 1.35 }, 0.1).to(hero2Ref.current, { opacity: 1, scale: 1.035, filter: "blur(0px)", ease: "none" }, 1.55).to(text1Ref.current, { opacity: 0, y: -34, scale: 0.985, filter: "blur(8px)", ease: "none" }, 1.78).to(text2Ref.current, { opacity: 1, y: 0, scale: 1, filter: "blur(0px)", ease: "none" }, 1.95).to(hero2Ref.current, { scale: 1.095, ease: "none" }, 2.5);
return () => {
if (videoEl) {
videoEl.pause();
videoEl.currentTime = 0;
}
darkHeroTrigger.kill();
document.body.classList.remove("is-dark-hero");
};
}, sectionRef);
return () => ctx.revert();
}, []);
return (
<section className="main-section" ref={sectionRef}>
<div className="main-bg-wrap">
<div className="main-bg" ref={bgRef}>
<div className="main-bg-hero1"></div>
<div className="main-bg-hero2" ref={hero2Ref}>
<video ref={videoRef} className="hero-video" src="./images/test.mp4" muted loop playsInline preload="auto" />
</div>
<div className="main-visible-atmo main-visible-atmo1"></div>
<div className="main-visible-atmo main-visible-atmo2"></div>
<div className="main-visible-beam main-visible-beam1"></div>
<div className="main-visible-beam main-visible-beam2"></div>
<div className="main-visible-haze"></div>
<div className="main-grid"></div>
<div className="main-text">
<div className="text text-fill text-left-bottom" ref={text1Ref}>
<span className="main-kicker">PAL NETWORKS</span>
<span className="fill-line">Technology Partner for</span>
<br />
<span className="fill-line">Advanced Air Mobility</span>
</div>
<div className="text text-change text-center-hero" ref={text2Ref}>
항공 데이터와 통합 관제 기술로
<br />
안전한 하늘길을 설계합니다
</div>
</div>
<div className="main-progress">
<span className="main-progress-bar" ref={progressBarRef}></span>
</div>
<div className="main-scroll-indicator">
<span className="main-scroll-line"></span>
<span className="main-scroll-text">SCROLL</span>
</div>
</div>
</div>
</section>
);
}
export default MainVisual;