Next.js · GSAP · Conic Mask

원형 마스크 회전 슬라이더


Overview

conic-gradient 마스크를 활용한 원형 슬라이더를 Next.js + GSAP으로 구현한 프로젝트입니다. 3중 동심원 이미지 레이어가 시차를 두고 스윕하며, SVG 오버레이 위에서 도트 · 틱 · 진행 원이 끊임없이 회전하는 고급 인터랙션을 프로덕션 수준의 아키텍처 위에 구현했습니다.

Feature-Sliced Design으로 슬라이더 전체 코드를 하나의 feature에 응집하고, 1,150줄 규모의 커스텀 훅이 conic-gradient 스윕 · RAF 연속 모션 · 자동 재생 · 입력 핸들링을 전담합니다. UI 컴포넌트는 순수한 렌더링만 담당하여 관심사 분리가 명확합니다.

Anatomy

UI 해부도

원형 슬라이더는 6개의 독립 UI 레이어로 구성됩니다. 3중 동심원 이미지 마스크 위에 SVG 오버레이가 겹치고, 하단 Info 영역과 원형 텍스트가 인터랙티브한 경험을 만들어냅니다.

PREVNEXT
SliderHeader
로고 · 네비게이션 링크
ImageLayers
3중 원형 마스크 이미지 레이어
SVG Overlay
동심원 · 진행 원 · 회전 도트 · 틱
SliderInfo
제목 · PREV/NEXT · 네온 라인
RadialText
원형 배치 슬라이드 이름 9개
SliderCounter
현재 / 전체 카운터 뱃지

Structure

프로젝트 아키텍처

Feature-Sliced Design 기반으로 원형 슬라이더의 모든 코드를 하나의 feature에 응집합니다. 1,150줄 규모의 애니메이션 훅이 전체 오케스트레이션을 전담하고, UI 컴포넌트는 순수한 렌더링만 담당합니다.

features/circular-sliderFSD
data/1
slides.json
10개 슬라이드 이미지 · 이름 데이터
hooks/1
useCircularSliderAnimation.ts
1150+ lines · 전체 애니메이션 엔진
ui/5
CircularSlider.tsx
3중 레이어 + SVG 오버레이 루트
SliderHeader.tsx
로고 + 네비게이션 헤더
SliderInfo.tsx
제목 + PREV/NEXT + 라인
SliderCounter.tsx
현재/전체 카운터 뱃지
SliderRadialText.tsx
원형 배치 슬라이드 이름
styles/1
circular-slider.css
CSS 변수 · radial text · progress

Data Flow

컴포넌트 데이터 플로우

데이터는 단방향으로 흐릅니다. JSON에서 시작해 1,150줄 규모의 커스텀 훅이 conic-gradient 마스킹과 연속 회전 애니메이션을 처리하고, UI 컴포넌트는 순수하게 렌더링만 담당합니다.

DATA
slides.json10개 슬라이드 객체image · name
HOOK
useCircularSliderAnimationgsap.context()goToSlide()RAF loop
UI
CircularSlider3 Image LayersSVG OverlaySub Components

ANIMATION OUTPUT

ImageLayers
원형 마스크 전환
conic-gradient sweep 3중
SVG Overlay
진행 원 + 도트 회전
stroke-dashoffset + RAF
SliderInfo
제목 · 라인 전환
fade + scaleX + neon flash
RadialText
원형 텍스트 회전
DOM insert/remove + CSS

Timeline

애니메이션 타임라인

슬라이드 전환은 약 0.82초 동안 7개의 애니메이션 레이어가 정밀하게 오케스트레이션됩니다. 3중 conic-gradient 마스크가 시차를 두고 스윕하며, 도트 가속과 네온 플래시가 전환감을 강화합니다.

0.0s0.1s0.2s0.3s0.4s0.5s0.6s0.7s0.8s
Title Exit
Outer Sweep
Mid Sweep
Inner Sweep
Dot Boost
Line Flash
Title Enter
이전 슬라이드 제목 퇴장 (0.3s fade)
외부 레이어 conic-gradient 스윕 + 1.3× 줌
중간 레이어 스윕 (70ms 딜레이) + 2× 줌
내부 레이어 스윕 (120ms 딜레이) + 2.2× 줌
회전 도트 가속 (BOOST 배수 적용)
네온 라인 scaleX 축소 → 확장 + 색상 플래시
새 슬라이드 제목 진입 (0.4s fade + offset)

Interaction

인터랙션 플로우

사용자 입력은 Wheel · Keyboard · Touch · Click 네 갈래로 분기됩니다. 모든 경로가 동일한 goToSlide()로 수렴하며, isAnimating 가드가 중복 실행을 차단합니다.

USER INTERACTION
Wheel
  1. 1

    deltaY 누적

    threshold: 50px
  2. 2

    방향 감지 → next / prev

Keyboard
  1. 1

    방향키 감지

    → ↓ next / ← ↑ prev
  2. 2

    즉시 goToSlide 호출

Touch
  1. 1

    touchStart 좌표 저장

    startY 기록
  2. 2

    touchEnd 스와이프 판정

    threshold: 50px
Click
  1. 1

    PREV / NEXT 버튼

    handlePrev · handleNext
goToSlide(nextIndex, direction)
3-Layer Conic Sweep + Title Transition외부 → 중간 → 내부 레이어 순차 스윕 + 제목 전환 (0.82s)

Patterns

핵심 기술 패턴

단순히 원형 전환이 아니라, 프로덕션에서 유지보수 가능한 구조로 설계했습니다. 3중 마스크 레이어 · RAF 연속 모션 · 커스텀 커서까지 — 고급 인터랙션의 실무 패턴을 담았습니다.

Conic-Gradient Mask
3중 원형 마스크 전환
conic-gradient로 각 레이어를 독립적으로 스윕 — 반지름별 radial-gradient 마스크와 조합하여 깊이감 있는 전환 구현
conic-gradient(from -90deg, black 0deg, black ${sweep}deg, transparent ${sweep}deg)
Progress Circle
SVG 자동 재생 인디케이터
stroke-dashoffset 애니메이션으로 5초 주기 progress 표시 — 완료 시 자동으로 다음 슬라이드 전환
gsap.to(circle, { strokeDashoffset: 0, duration: 5 })
RAF Continuous Motion
끊김 없는 연속 회전
requestAnimationFrame 루프에서 3개 도트 + 틱 마크를 독립된 속도로 연속 회전 — 슬라이드 전환과 무관하게 항상 동작
innerDotAngle += 0.005 midDotAngle += 0.003 outerDotAngle += 0.002
Custom Cursor
GSAP quickSetter 커서
gsap.quickSetter()로 dot + ring 위치를 서브밀리초 단위로 업데이트 — ring은 lerp 추적으로 부드러운 체이스 연출
gsap.quickSetter(dot, 'css') ticker.add(() => lerp(ring, mouse))
Stagger Delay
레이어별 시차 스윕
외부 0ms → 중간 70ms → 내부 120ms 딜레이로 3중 레이어가 시차를 두고 스윕 — 줌 배율도 1.3× → 2× → 2.2× 차등 적용
outer: 0ms, 0.6s, 1.3× mid: 70ms, 0.75s, 2× inner: 120ms, 0.6s, 2.2×
Radial Text
CSS 기반 원형 텍스트
9개 텍스트 슬롯을 nth-child CSS로 회전 · 투명도 · 크기 제어 — 슬라이드 전환 시 DOM insert/remove로 순환
:nth-child(5) { rotate: 0deg; opacity: 1; font-size: 1.4rem; }

Responsive

반응형 전략

데스크탑 퍼스트로 설계하고 max-xl · max-md 2단계 브레이크포인트만 사용합니다. 모바일에서는 Radial Text와 커스텀 커서를 비활성화하여 터치 중심 경험을 제공합니다.

Desktop1280px+
  • Radial Text 원형 배치
  • 커스텀 커서 (dot + ring)
  • 풀 네비게이션 표시
  • 카운터 우하단 고정
  • Wheel + 키보드 입력
Tabletmax-xl~1280px
  • Radial Text 유지
  • 간격 · 패딩 축소
  • 폰트 사이즈 조정
  • 네비게이션 유지
  • 터치 스와이프 추가
Mobilemax-md~768px
  • Radial Text 숨김
  • 네비게이션 숨김
  • 커스텀 커서 비활성
  • 카운터 축소 · 위치 조정
  • 터치 스와이프 전용