From d56c0f974cdbe046c1e76e7533a130188821bd04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?siyeon00=28=EC=9D=B4=EC=8B=9C=EC=97=B0=29?= Date: Tue, 1 Sep 2026 11:08:11 +0900 Subject: [PATCH] =?UTF-8?q?fix=20:=20=EB=A9=94=EC=9D=B8=20=ED=95=B4?= =?UTF-8?q?=EC=83=81=EB=8F=84=20=EA=B9=A8=EC=A7=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/main/MainUam.jsx | 73 ++++++++++++++++++++++++++++----- src/css/main.css | 19 +++++---- 2 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/components/main/MainUam.jsx b/src/components/main/MainUam.jsx index 3bec060..59d421f 100644 --- a/src/components/main/MainUam.jsx +++ b/src/components/main/MainUam.jsx @@ -58,7 +58,6 @@ function MainUam() { const dotRef = useRef(null); const uamImageRef = useRef(null); const canvasRef = useRef(null); - const isMobile = window.innerWidth <= 768; useEffect(() => { // ── 배경 캔버스 ───────────────────────────────────────── @@ -97,7 +96,14 @@ function MainUam() { const steps = 200; const ampScale = mobile ? 0.35 : 0.5 + scrollP * 0.7; - const pts = Array.from({ length: steps + 1 }, (_, s) => [(s / steps) * W, canvas.height * w.yRatio + Math.sin((s / steps) * Math.PI * w.freq + ts * w.speed + w.phase) * w.amp * canvas.height * ampScale]); + const pts = Array.from({ length: steps + 1 }, (_, s) => [ + (s / steps) * W, + canvas.height * w.yRatio + + Math.sin((s / steps) * Math.PI * w.freq + ts * w.speed + w.phase) * + w.amp * + canvas.height * + ampScale, + ]); const alphaCenter = scrollP * (mobile ? 0.12 : 0.18); const grad = c.createLinearGradient(0, 0, W, 0); @@ -128,7 +134,14 @@ function MainUam() { const ampScale = mobile ? 0.35 : 0.5 + scrollP * 0.7; const x = d.t * W; - const y = canvas.height * d.wave.yRatio + Math.sin(d.t * Math.PI * d.wave.freq + ts * d.wave.speed + d.wave.phase) * d.wave.amp * canvas.height * ampScale; + const y = + canvas.height * d.wave.yRatio + + Math.sin( + d.t * Math.PI * d.wave.freq + ts * d.wave.speed + d.wave.phase, + ) * + d.wave.amp * + canvas.height * + ampScale; const edgeFade = Math.sin(d.t * Math.PI); const alpha = edgeFade * scrollP * 0.45; if (alpha < 0.01) return; @@ -167,12 +180,35 @@ function MainUam() { window.addEventListener("resize", resize); raf = requestAnimationFrame(draw); + const getCoverScale = () => { + const section = sectionRef.current; + const dot = dotRef.current; + + if (!section || !dot) return 1; + + const sectionWidth = section.clientWidth; + const sectionHeight = section.clientHeight; + + // translate(-50%, -50%)를 사용하므로 left와 top이 원의 중심 + const centerX = dot.offsetLeft; + const centerY = dot.offsetTop; + + const farthestX = Math.max(centerX, sectionWidth - centerX); + const farthestY = Math.max(centerY, sectionHeight - centerY); + const requiredRadius = Math.hypot(farthestX, farthestY); + + // 모서리에 미세한 틈이 생기지 않도록 8% 여유 + return (requiredRadius / (dot.offsetWidth / 2)) * 1.08; + }; + // ── GSAP 기존 애니메이션 ──────────────────────────────── const ctx = gsap.context(() => { gsap.set(rightRef.current, { xPercent: 100 }); gsap.set(lineRef.current, { scaleX: 0, transformOrigin: "left center" }); gsap.set(dotRef.current, { - x: isMobile ? -160 : -320, + xPercent: -50, + yPercent: -50, + x: window.innerWidth <= 768 ? -160 : -320, opacity: 0, scale: 1, }); @@ -187,6 +223,7 @@ function MainUam() { scrub: 1, pin: true, anticipatePin: 1, + invalidateOnRefresh: true, }, }); @@ -197,7 +234,11 @@ function MainUam() { ease: "none", }); - tl.to(dotRef.current, { x: 0, opacity: 1, duration: 0.7, ease: "none" }, "<0.1"); + tl.to( + dotRef.current, + { x: 0, opacity: 1, duration: 0.7, ease: "none" }, + "<0.1", + ); tl.to(leftRef.current, { xPercent: -100, duration: 1, ease: "none" }); tl.to(rightRef.current, { xPercent: 0, duration: 1, ease: "none" }, "<"); @@ -209,12 +250,22 @@ function MainUam() { tl.to(dotRef.current, { x: 0, y: 0, - scale: isMobile ? 42 : 52, + scale: () => getCoverScale(), duration: 1.2, ease: "power2.inOut", }); - tl.to([".airspace-uam-content", uamImageRef.current], { opacity: 1, y: 0, duration: 0.8, ease: "power2.out" }, "-=0.35"); + tl.to( + ".airspace-uam-content", + { opacity: 1, y: 0, duration: 0.8, ease: "power2.out" }, + ">", + ); + + tl.to( + uamImageRef.current, + { opacity: 1, duration: 0.8, ease: "power2.out" }, + "<", + ); }, sectionRef); return () => { @@ -252,10 +303,10 @@ function MainUam() { ))} -
-
- UAM Aircraft -
+
+ +
+ UAM Aircraft
diff --git a/src/css/main.css b/src/css/main.css index e2c65c5..dfd9ca5 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -248,27 +248,28 @@ body{overflow-x:hidden;} .airspace-moving-dot, .airspace-uam-content {position: relative; z-index: 1; } -.airspace-transition-section{position:relative;min-height:100vh;overflow:hidden;background:radial-gradient(circle at 12% 8%,rgba(26,31,94,.04),transparent 30%),radial-gradient(circle at 88% 10%,rgba(26,31,94,.035),transparent 32%),linear-gradient(180deg,#ffffff 0%,#f7f9ff 48%,#ffffff 100%);} +.airspace-transition-section{--uam-center-x:68%;--uam-center-y:49%;position:relative;min-height:100vh;overflow:hidden;background:radial-gradient(circle at 12% 8%,rgba(26,31,94,.04),transparent 30%),radial-gradient(circle at 88% 10%,rgba(26,31,94,.035),transparent 32%),linear-gradient(180deg,#ffffff 0%,#f7f9ff 48%,#ffffff 100%);} .airspace-transition-section::before{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(255,255,255,.72) 0%,rgba(255,255,255,.24) 20%,rgba(255,255,255,.08) 50%,rgba(255,255,255,.24) 80%,rgba(255,255,255,.72) 100%);pointer-events:none;} .airspace-panel{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:center;padding:0 8vw;} .airspace-panel--utm{background:transparent;} -.airspace-panel--UTM{background:radial-gradient(circle at 72% 34%,rgba(112,180,255,.12),transparent 34%),radial-gradient(circle at 42% 78%,rgba(26,31,94,.08),transparent 28%);} +.airspace-panel--uam{background:radial-gradient(circle at 72% 34%,rgba(112,180,255,.12),transparent 34%),radial-gradient(circle at 42% 78%,rgba(26,31,94,.08),transparent 28%);} .airspace-panel p{margin:0 0 18px;font-size:12px;font-weight:800;letter-spacing:.26em;color:#1a1f5e;} .airspace-panel h2{margin:0;max-width:760px;font-size:clamp(48px,6vw,96px);font-weight:800;line-height:.96;letter-spacing:-.08em;color:#0e1120;} .airspace-lines{position:absolute;inset:0;z-index:5;pointer-events:none;} -.airspace-moving-dot{position:absolute;left:68%;top:49%;z-index:6;width:54px;height:54px;border-radius:50%;background:#1a1f5e;border:1px solid rgba(26,31,94,.14);box-shadow:0 0 0 12px rgba(26,31,94,.06),0 20px 50px rgba(26,31,94,.18);transform-origin:center center;} -.airspace-moving-dot::before{content:"";position:absolute;inset:20px;border-radius:50%;background:#ffffff;opacity:.9;} - +.airspace-moving-dot{position:absolute;left:var(--uam-center-x);top:var(--uam-center-y);z-index:6;width:54px;height:54px;min-width:54px;min-height:54px;aspect-ratio:1/1;border-radius:50%;background:#1a1f5e;border:1px solid rgba(26,31,94,.14);box-shadow:0 0 0 12px rgba(26,31,94,.06),0 20px 50px rgba(26,31,94,.18);transform:translate(-50%,-50%);transform-origin:center center;} +.airspace-moving-dot::before{content:"";position:absolute;left:50%;top:50%;width:14px;height:14px;aspect-ratio:1/1;border-radius:50%;background:#ffffff;opacity:.9;transform:translate(-50%,-50%);} .airspace-uam-content{position:absolute;left:8vw;top:50%;transform:translateY(-50%);z-index:20;max-width:760px;color:#ffffff;pointer-events:none;} .airspace-uam-content p{margin:0 0 18px;font-size:12px;font-weight:800;letter-spacing:.28em;color:rgba(255,255,255,.72);} .airspace-uam-content h2{margin:0 0 24px;font-size:clamp(54px,7vw,104px);font-weight:800;line-height:.92;letter-spacing:-.07em;color:#ffffff;} .airspace-uam-content span{display:block;max-width:560px;font-size:18px;line-height:1.8;font-weight:500;color:rgba(255,255,255,.72);} -.airspace-dot-image{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;opacity:0;z-index:2;pointer-events:none;} -.airspace-dot-image img{width:32%;height:32%;object-fit:contain;filter:drop-shadow(0 8px 32px rgba(26,31,94,.28));animation:float-UTM 5s ease-in-out infinite;will-change:transform;} +.airspace-dot-image{position:absolute;left:var(--uam-center-x);top:var(--uam-center-y);z-index:7;width:clamp(560px,36vw,700px);opacity:0;pointer-events:none;transform:translate(-50%,-50%);} +.airspace-dot-image img{display:block;width:100%;height:auto;object-fit:contain;filter:drop-shadow(0 8px 32px rgba(26,31,94,.28));animation:uamAircraftFloat 3.2s ease-in-out infinite;transform-origin:center center;will-change:transform;} .airspace-mobile-br{display:none;} @media (max-width:768px){ + .airspace-transition-section{--uam-center-x:88%;--uam-center-y:43%;}.airspace-dot-image{width:min(88vw,480px);} + .airspace-moving-dot{left:88%;top:43%;transform:translate(-50%,-50%);} .airspace-dot-UTM{width:110px;} .airspace-uam-content{left:0;right:0;top:auto;bottom:7%;transform:none;padding:0 6vw;max-width:100%;} @@ -279,6 +280,7 @@ body{overflow-x:hidden;} } @media (min-width:769px) and (max-width:1024px){ + .airspace-transition-section{--uam-center-x:82%;--uam-center-y:50%;}.airspace-dot-image{width:min(58vw,620px);} .airspace-moving-dot{left:82%;top:50%;transform:translate(-50%,-50%);} .airspace-dot-UTM{width:280px;} .airspace-uam-content{left:4%;right:auto;top:auto;bottom:10%;transform:none;padding:0 4vw;max-width:60%;} @@ -289,8 +291,7 @@ body{overflow-x:hidden;} } @keyframes UTMShine{0%,48%{transform:translateX(-120%);opacity:0;}58%{opacity:.75;}76%,100%{transform:translateX(120%);opacity:0;}} -@keyframes float-UTM{0%{transform:translateY(0px);}48%{transform:translateY(-1px);}100%{transform:translateY(0px);}} - +@keyframes uamAircraftFloat{0%,100%{transform:translateY(10px) rotate(.3deg);}50%{transform:translateY(-28px) rotate(-.3deg);}} /* ─── SOLUTION ─── */ .main-solution-section { position: relative; height: auto; min-height: 100dvh; overflow: visible; padding: 120px 8vw 160px; background: linear-gradient(180deg,#ffffff 0%,#f7f9ff 52%,#ffffff 100%); }