diff --git a/index.html b/index.html index e4d6dd3..8894b83 100644 --- a/index.html +++ b/index.html @@ -3,23 +3,14 @@ - + - + - + @@ -43,10 +34,7 @@ - + diff --git a/public/images/uam.png b/public/images/uam.png new file mode 100644 index 0000000..458281d Binary files /dev/null and b/public/images/uam.png differ diff --git a/src/components/main/MainUam.jsx b/src/components/main/MainUam.jsx new file mode 100644 index 0000000..c1c3ef6 --- /dev/null +++ b/src/components/main/MainUam.jsx @@ -0,0 +1,330 @@ +import { useEffect, useRef } from "react"; +import { gsap } from "gsap"; +import { ScrollTrigger } from "gsap/ScrollTrigger"; + +gsap.registerPlugin(ScrollTrigger); + +const UAM_SPECS = [ + { + id: "01", + anchor: "navigation", + label: "자율 항법 시스템", + title: "AI 기반\n정밀 항법", + desc: "다중 센서 융합과 실시간 AI 연산으로 도심 상공에서도 센티미터 단위의 정밀 경로 제어를 실현합니다.", + stat: "±0.03m", + statLabel: "위치 정확도", + cx: "28%", + cy: "38%", + cardSide: "left", + }, + { + id: "02", + anchor: "comm", + label: "통합 통신 모듈", + title: "5G·위성\n이중 통신", + desc: "5G와 위성 통신을 동시에 운용하는 이중 링크 구조로 어떤 환경에서도 끊김 없는 데이터 채널을 보장합니다.", + stat: "<8ms", + statLabel: "지연 시간", + cx: "72%", + cy: "30%", + cardSide: "right", + }, + { + id: "03", + anchor: "power", + label: "하이브리드 추진", + title: "전기·수소\n하이브리드", + desc: "전기 모터와 수소 셀을 결합한 하이브리드 추진 시스템으로 항속 거리를 극대화하고 탄소 배출을 최소화합니다.", + stat: "320km", + statLabel: "최대 항속", + cx: "50%", + cy: "72%", + cardSide: "left", + }, + { + id: "04", + anchor: "sensor", + label: "능동 안전 센서", + title: "360° 장애물\n회피", + desc: "LiDAR·레이더·광학 카메라 트리플 센서가 360도 전방위를 실시간 스캔해 돌발 장애물에 즉각 대응합니다.", + stat: "0.12s", + statLabel: "반응 속도", + cx: "78%", + cy: "65%", + cardSide: "right", + }, +]; + +function MainUam() { + const sectionRef = useRef(null); + const eyebrowRef = useRef(null); + const titleRef = useRef(null); + const subRef = useRef(null); + const aircraftRef = useRef(null); + const dotRefs = useRef([]); + const lineRefs = useRef([]); + const cardRefs = useRef([]); + + useEffect(() => { + const ctx = gsap.context(() => { + dotRefs.current = dotRefs.current.slice(0, UAM_SPECS.length); + lineRefs.current = lineRefs.current.slice(0, UAM_SPECS.length); + cardRefs.current = cardRefs.current.slice(0, UAM_SPECS.length); + + gsap.set(aircraftRef.current, { + opacity: 0, + scale: 0.72, + x: "-18vw", + y: "12vh", + }); + + gsap.set(eyebrowRef.current, { + opacity: 0, + y: 28, + filter: "blur(8px)", + }); + + gsap.set(titleRef.current, { + opacity: 0, + y: 36, + filter: "blur(8px)", + }); + + gsap.set(subRef.current, { + opacity: 0, + y: 24, + }); + + cardRefs.current.forEach((el) => { + if (el) gsap.set(el, { opacity: 0, y: 28, scale: 0.96, filter: "blur(6px)" }); + }); + + dotRefs.current.forEach((el) => { + if (el) gsap.set(el, { scale: 0, opacity: 0 }); + }); + + lineRefs.current.forEach((el) => { + if (el) gsap.set(el, { scaleX: 0, opacity: 0 }); + }); + + ScrollTrigger.matchMedia({ + "(min-width: 992px)": () => { + const tl = gsap.timeline({ + scrollTrigger: { + trigger: sectionRef.current, + start: "top top", + end: "+=3200", + scrub: 1.05, + pin: true, + anticipatePin: 1, + invalidateOnRefresh: true, + }, + }); + + tl.to(eyebrowRef.current, { opacity: 1, y: 0, filter: "blur(0px)", ease: "none", duration: 0.5 }, 0).to(titleRef.current, { opacity: 1, y: 0, filter: "blur(0px)", ease: "none", duration: 0.65 }, 0.08).to(subRef.current, { opacity: 1, y: 0, ease: "none", duration: 0.45 }, 0.22).to( + aircraftRef.current, + { + opacity: 1, + scale: 1, + x: 0, + y: 0, + ease: "none", + duration: 1.8, + }, + 0.12, + ); + + UAM_SPECS.forEach((spec, i) => { + const baseTime = 0.5 + i * 0.52; + const origin = spec.cardSide === "left" ? "right center" : "left center"; + + tl.to( + dotRefs.current[i], + { + scale: 1, + opacity: 1, + ease: "none", + duration: 0.18, + }, + baseTime, + ) + .to( + lineRefs.current[i], + { + scaleX: 1, + opacity: 1, + transformOrigin: origin, + ease: "none", + duration: 0.24, + }, + baseTime + 0.08, + ) + .to( + cardRefs.current[i], + { + opacity: 1, + y: 0, + scale: 1, + filter: "blur(0px)", + ease: "none", + duration: 0.32, + }, + baseTime + 0.18, + ); + }); + + tl.to( + aircraftRef.current, + { + scale: 1.05, + ease: "none", + duration: 0.45, + }, + 2.7, + ); + }, + + "(max-width: 991px)": () => { + const tl = gsap.timeline({ + scrollTrigger: { + trigger: sectionRef.current, + start: "top 80%", + end: "bottom 30%", + scrub: 0.8, + invalidateOnRefresh: true, + }, + }); + + tl.to(eyebrowRef.current, { opacity: 1, y: 0, filter: "blur(0px)", ease: "none", duration: 0.22 }, 0) + .to(titleRef.current, { opacity: 1, y: 0, filter: "blur(0px)", ease: "none", duration: 0.24 }, 0.05) + .to(subRef.current, { opacity: 1, y: 0, ease: "none", duration: 0.2 }, 0.1) + .to( + aircraftRef.current, + { + opacity: 1, + scale: 1, + x: 0, + y: 0, + ease: "none", + duration: 0.28, + }, + 0.16, + ) + .to( + dotRefs.current, + { + scale: 1, + opacity: 1, + stagger: 0.05, + ease: "none", + duration: 0.18, + }, + 0.24, + ) + .to( + lineRefs.current, + { + scaleX: 1, + opacity: 1, + stagger: 0.05, + ease: "none", + duration: 0.18, + }, + 0.3, + ) + .to( + cardRefs.current, + { + opacity: 1, + y: 0, + scale: 1, + filter: "blur(0px)", + stagger: 0.06, + ease: "none", + duration: 0.2, + }, + 0.36, + ); + }, + }); + + gsap.to(aircraftRef.current, { + y: -8, + duration: 2.8, + ease: "sine.inOut", + repeat: -1, + yoyo: true, + }); + }, sectionRef); + + return () => ctx.revert(); + }, []); + + return ( +
+
+
+
+ +
+
+
+ + UAM TECHNOLOGY +
+ +

+ 도심 항공 모빌리티, +
+ 기술로 완성합니다 +

+ +

+ PAL NETWORKS의 4대 핵심 기술이 안전한 하늘길을 만듭니다 +

+
+ +
+
+ UAM 기체 +
+
+ + {UAM_SPECS.map((spec, i) => ( +
+
(dotRefs.current[i] = el)} style={{ left: spec.cx, top: spec.cy }}> + + +
+ +
(lineRefs.current[i] = el)} style={{ left: spec.cx, top: spec.cy }}>
+ +
(cardRefs.current[i] = el)} style={{ left: spec.cx, top: `calc(${spec.cy} - 10px)` }}> +
{spec.id}
+
{spec.label}
+ + + {spec.title.split("\n").map((line, j) => ( + + {line} + {j === 0 &&
} +
+ ))} +
+ +

{spec.desc}

+ +
+ {spec.stat} + {spec.statLabel} +
+
+
+ ))} +
+
+
+ ); +} + +export default MainUam; diff --git a/src/components/main/MainUtm.jsx b/src/components/main/MainUtm.jsx index 49cb847..e30148e 100644 --- a/src/components/main/MainUtm.jsx +++ b/src/components/main/MainUtm.jsx @@ -5,7 +5,7 @@ import { ScrollTrigger } from "gsap/ScrollTrigger"; gsap.registerPlugin(ScrollTrigger); function MainUtm() { - return
utm uam
; + return
utm uam
; } export default MainUtm; diff --git a/src/components/main/MainVisual.jsx b/src/components/main/MainVisual.jsx index 7bb1940..da5a824 100644 --- a/src/components/main/MainVisual.jsx +++ b/src/components/main/MainVisual.jsx @@ -56,6 +56,8 @@ function MainVisual() { pin: true, anticipatePin: 1, onUpdate: (self) => { + gsap.set(progressBarRef.current, { width: `${self.progress * 100}%` }); + if (!videoEl) return; if (self.progress >= 0.42 && !hero2Started) { @@ -73,15 +75,7 @@ function MainVisual() { }, }); - tl.to(bgRef.current, { width: "100vw", height: "100vh", borderRadius: 0, ease: "none" }, 0) - .to(bgRef.current, { scale: 1.08, ease: "none" }, 0) - .to(progressBarRef.current, { width: "100%", 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); + 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) { @@ -95,7 +89,6 @@ function MainVisual() { return () => ctx.revert(); }, []); - return (
diff --git a/src/css/common.css b/src/css/common.css index c4eb671..4c9b3c0 100644 --- a/src/css/common.css +++ b/src/css/common.css @@ -17,6 +17,7 @@ body{overflow-x:hidden;} .main-layout{min-height:calc(100vh - var(--header-height));padding-top:var(--header-height);} .sub-layout{min-height:calc(100vh - var(--header-height));padding-top:var(--header-height);} +/*main visual*/ .main-page{width:100%;overflow:hidden;} .main-section{position:relative;height:100vh;} .main-bg-wrap{position:relative;width:100%;height:100vh;display:flex;align-items:flex-start;justify-content:center;overflow:hidden;} @@ -135,3 +136,93 @@ body{overflow-x:hidden;} .main-scroll-text{font-size:10px;letter-spacing:.22em;} } +/*main uam*/ + +.uam-section{position:relative;width:100%;height:100vh;background:#f7f9ff;overflow:hidden;} +.uam-bg-grid{position:absolute;inset:0;pointer-events:none;background-image:linear-gradient(rgba(58,64,129,.045) 1px,transparent 1px),linear-gradient(90deg,rgba(58,64,129,.045) 1px,transparent 1px);background-size:56px 56px;mask-image:radial-gradient(ellipse 80% 80% at 50% 50%,black 30%,transparent 100%);opacity:.7;} +.uam-bg-glow{position:absolute;pointer-events:none;border-radius:50%;filter:blur(80px);} +.uam-bg-glow--a{width:640px;height:640px;top:-120px;right:-80px;background:radial-gradient(circle,rgba(58,64,129,.12) 0%,rgba(58,64,129,0) 70%);} +.uam-bg-glow--b{width:500px;height:500px;bottom:-100px;left:-60px;background:radial-gradient(circle,rgba(112,180,255,.1) 0%,rgba(112,180,255,0) 70%);} + +.uam-inner{position:relative;z-index:2;width:100%;height:100%;display:flex;flex-direction:column;align-items:center;padding:0 40px;} +.uam-header{position:absolute;top:clamp(48px,7vh,80px);left:50%;transform:translateX(-50%);text-align:center;z-index:4;pointer-events:none;width:min(760px,calc(100% - 80px));} +.uam-eyebrow{display:inline-flex;align-items:center;gap:8px;margin-bottom:16px;font-size:11px;font-weight:700;letter-spacing:.22em;color:var(--color-primary);will-change:transform,opacity,filter;} +.uam-eyebrow-dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--color-primary);opacity:.7;} +.uam-title{margin:0;font-size:clamp(32px,3.6vw,58px);font-weight:700;line-height:1.14;letter-spacing:-.05em;color:#0e1120;will-change:transform,opacity,filter;} +.uam-title em{font-style:normal;color:var(--color-primary);} +.uam-sub{margin:14px 0 0;font-size:15px;line-height:1.6;color:#7a8198;letter-spacing:-.01em;will-change:transform,opacity;} + +.uam-stage{position:absolute;inset:0;z-index:3;} +.uam-aircraft-wrap{position:absolute;left:50%;top:50%;transform:translate(-50%,-44%);z-index:5;will-change:transform,opacity;pointer-events:none;} +.uam-aircraft-img{display:block;width:clamp(320px,42vw,640px);height:auto;object-fit:contain;filter:drop-shadow(0 32px 64px rgba(14,17,32,.18)) drop-shadow(0 8px 18px rgba(58,64,129,.14));user-select:none;} +.uam-aircraft-shadow{position:absolute;bottom:-24px;left:50%;transform:translateX(-50%);width:68%;height:28px;background:radial-gradient(ellipse,rgba(14,17,32,.16) 0%,transparent 72%);filter:blur(8px);border-radius:50%;} + +.uam-point-group{position:absolute;inset:0;pointer-events:none;} +.uam-dot{position:absolute;width:14px;height:14px;transform:translate(-50%,-50%);z-index:6;will-change:transform,opacity;} +.uam-dot-ring{position:absolute;inset:-5px;border-radius:50%;border:1.5px solid rgba(58,64,129,.35);animation:uamDotPulse 2.4s ease-in-out infinite;} +.uam-dot-core{position:absolute;inset:2px;border-radius:50%;background:var(--color-primary);box-shadow:0 0 10px rgba(58,64,129,.5);} + +.uam-line{position:absolute;height:1px;width:44px;top:0;background:linear-gradient(90deg,var(--color-primary),rgba(58,64,129,.25));z-index:5;will-change:transform,opacity;} +.uam-line--left{transform:translate(-44px,-50%);transform-origin:right center;} +.uam-line--right{transform:translate(0,-50%);transform-origin:left center;} + +.uam-card{position:absolute;width:clamp(210px,16vw,264px);padding:18px 20px 20px;border-radius:20px;background:rgba(255,255,255,.82);backdrop-filter:blur(20px);border:1px solid rgba(58,64,129,.1);box-shadow:0 4px 6px rgba(14,17,32,.04),0 16px 40px rgba(14,17,32,.08),inset 0 1px 0 rgba(255,255,255,.9);z-index:6;will-change:transform,opacity,filter;transition:box-shadow .3s ease;} +.uam-card::before{content:"";position:absolute;inset:0;border-radius:inherit;background:linear-gradient(135deg,rgba(255,255,255,.6) 0%,rgba(255,255,255,0) 60%);pointer-events:none;} +.uam-card--left{transform:translate(calc(-100% - 30px),-50%);} +.uam-card--right{transform:translate(30px,-50%);} + +.uam-card-index{display:inline-flex;align-items:center;justify-content:center;width:28px;height:18px;margin-bottom:10px;border-radius:999px;background:rgba(58,64,129,.08);font-size:10px;font-weight:800;letter-spacing:.1em;color:var(--color-primary);} +.uam-card-label{font-size:10px;font-weight:700;letter-spacing:.16em;color:rgba(58,64,129,.6);margin-bottom:6px;text-transform:uppercase;} +.uam-card-title{display:block;font-size:17px;font-weight:700;line-height:1.3;letter-spacing:-.03em;color:#0e1120;margin-bottom:10px;} +.uam-card-desc{margin:0 0 14px;font-size:12.5px;line-height:1.72;color:#667085;word-break:keep-all;} +.uam-card-stat{display:flex;align-items:baseline;gap:7px;padding-top:12px;border-top:1px solid rgba(58,64,129,.08);} +.uam-card-stat-value{font-size:22px;font-weight:800;letter-spacing:-.04em;color:var(--color-primary);line-height:1;} +.uam-card-stat-label{font-size:11px;font-weight:600;color:#a0a9bc;letter-spacing:.04em;} + +@keyframes uamDotPulse{ +0%{transform:scale(1);opacity:.5;} +50%{transform:scale(1.6);opacity:0;} +100%{transform:scale(1);opacity:.5;} +} + +@media (max-width:1280px){ +.uam-aircraft-img{width:clamp(280px,40vw,520px);} +.uam-card{width:clamp(190px,15vw,240px);padding:16px 18px 18px;} +.uam-card--left{transform:translate(calc(-100% - 24px),-50%);} +.uam-card--right{transform:translate(24px,-50%);} +.uam-card-title{font-size:15px;} +.uam-card-desc{font-size:12px;} +.uam-card-stat-value{font-size:20px;} +} + +@media (max-width:991px){ +.uam-title{font-size:clamp(28px,5vw,42px);} +.uam-aircraft-img{width:clamp(240px,52vw,400px);} +.uam-card{width:clamp(170px,22vw,210px);padding:14px 15px 16px;} +.uam-card--left{transform:translate(calc(-100% - 18px),-50%);} +.uam-card--right{transform:translate(18px,-50%);} +.uam-card-title{font-size:14px;} +.uam-card-desc{font-size:11.5px;line-height:1.62;} +.uam-card-stat-value{font-size:18px;} +} + +@media (max-width:768px){ +.uam-inner{padding:0 16px;} +.uam-header{top:clamp(36px,5vh,52px);width:calc(100% - 32px);} +.uam-title{font-size:clamp(26px,7vw,36px);} +.uam-sub{font-size:13px;margin-top:10px;} +.uam-aircraft-img{width:clamp(200px,72vw,340px);} +.uam-aircraft-wrap{top:50%;transform:translate(-50%,-46%);} +.uam-dot{width:10px;height:10px;} +.uam-line{width:26px;} +.uam-line--left{transform:translate(-26px,-50%);} +.uam-card{width:clamp(148px,38vw,180px);padding:12px 13px 14px;border-radius:16px;} +.uam-card--left{transform:translate(calc(-100% - 12px),-50%);} +.uam-card--right{transform:translate(12px,-50%);} +.uam-card-index{width:24px;height:16px;font-size:9px;} +.uam-card-label{font-size:9px;} +.uam-card-title{font-size:12px;margin-bottom:7px;} +.uam-card-desc{font-size:10.5px;line-height:1.58;margin-bottom:10px;} +.uam-card-stat-value{font-size:16px;} +.uam-card-stat-label{font-size:10px;} +} \ No newline at end of file diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx index 7f0820b..48823ba 100644 --- a/src/pages/MainPage.jsx +++ b/src/pages/MainPage.jsx @@ -1,11 +1,13 @@ import MainVisual from "../components/main/MainVisual"; import MainUtm from "../components/main/MainUtm"; +import MainUam from "../components/main/MainUam"; function MainPage() { return (
- + {/* */} +
); }