Next.js · GSAP · SplitText · 3D Perspective

스크롤 시 흩어지는 3D 텍스트


Overview

300vh 높이의 sticky 섹션에서 3D perspective 텍스트 비행 애니메이션을 구현한 프로젝트입니다. SplitText로 분리된 27개의 글자·단어가 z축 550~1350 깊이에서 화면으로 수렴한 뒤, 스크롤 퇴장 시 다시 발산하는 3단계 플라이 패턴을 구현했습니다.

heading은 chars로, body는 words로 이중 분할하여 서로 다른 밀도의 3D 효과를 적용하고, Math.random() 기반 스태거 순서로 각 요소의 등장 타이밍을 자연스럽게 분산합니다. 좌측의 그라디언트 Orb 구성과 함께 시각적 깊이감을 극대화한 스크롤 섹션입니다.

Anatomy

UI 해부도

SectionScatter는 sticky 컨테이너 안에서 좌측 Orb 구성과 우측 3D 플라이 텍스트가 결합된 2단 레이아웃입니다. 27개의 글자·단어가 z축 깊이에서 화면으로 수렴하는 perspective 애니메이션이 핵심입니다.

sticky · 300vh
2026
Main Orb
그라디언트 구체 · 스크롤 회전
Small Orb
핑크 구체 · 궤도 회전
Year Text
2026 배경 텍스트 · x 드리프트
Heading Chars
SplitText chars · 3D fly-in/out
Body Words
SplitText words · 3D fly-in/out
Info Grid
Role · Tools · E-Mail · Designer

Structure

프로젝트 아키텍처

SectionScatter는 하나의 컴포넌트 안에서 SplitText · ScrollTrigger · 랜덤 데이터를 조합하여 3D 플라이 애니메이션을 구현합니다. 27개 요소의 랜덤 값은 컴포넌트 상단 상수로 분리되어 있습니다.

components/GSAP
section/1
SectionScatter.tsx
300vh 섹션 · 3D fly 애니메이션 · ScrollTrigger
text/1
SplitText (GSAP)
heading → chars, body → words 분할
orbs/1
BgOrbs.jsx
scatterText 프리셋 배경 블롭
data/3
staggerOrder[]
27개 랜덤 순서값 (0~1)
wordRotateX[]
27개 랜덤 rotateX (-80°~80°)
wordTranslateZ[]
27개 랜덤 z 오프셋 (550~1350)

Data Flow

컴포넌트 데이터 플로우

데이터는 3단계로 흐릅니다. SplitText로 텍스트를 분할하고, 초기 3D 상태를 설정한 뒤, ScrollTrigger가 스크롤 progress에 따라 fly-in · rest · fly-out을 제어합니다.

SPLIT
SplitText.createheading → charsbody → words
INIT
setInitialFlyStatez: 550~1350rotateX: randomopacity: 0
SCROLL
ScrollTrigger scrub:2fly-in phaserest phasefly-out phase

ANIMATION OUTPUT

chars
3D 플라이인
z → 0, rotateX → 0, stagger
words
3D 플라이인
z → 0, rotateX → 0, stagger
mainOrb
회전
rotation: progress × 30°
smallOrb
궤도 회전
rotation: progress × 120°, origin 250%

Timeline

애니메이션 타임라인

스크롤 진행률 0%~100% 구간에서 5개의 애니메이션 레이어가 동시에 진행됩니다. 텍스트는 fly-in · rest · fly-out 3단계로 분리되고, Orb와 Year는 전 구간에서 지속 회전합니다.

0%20%40%60%80%100%
Fly-In
Rest
Fly-Out
Orb Rotation
Year Drift
chars + words z:1350→0 순차 수렴 (stagger 랜덤)
z:0에서 정지 — 텍스트 읽기 구간
chars + words z:0→1350 순차 발산 (stagger 랜덤)
main 30° + small 120° 회전
x: (progress-0.5) × 300 좌우 드리프트

Interaction

인터랙션 플로우

스크롤 progress 값에 따라 3개의 페이즈로 분기됩니다. 각 페이즈는 임계값(flyInEnd, flyOutStart)을 기준으로 전환되며, 27개 요소의 랜덤 스태거 순서가 자연스러운 등장·퇴장 타이밍을 만듭니다.

SCROLL START
progress 구간 판정
Fly-In PhaseIN
  1. 1

    staggerOrder로 요소별 딜레이 계산

    delay = order × 0.6
  2. 2

    z값 보간: translateZ → 0

    z: interpolate(tz, 0, eased)
  3. 3

    깊이 기반 opacity 계산

    opacity: 1 - z / 350
Rest PhaseREST
  1. 1

    모든 요소 z:0 고정

    translateZ: 0
  2. 2

    opacity:1, rotateX:0

    텍스트 읽기 구간
  3. 3

    Orb 회전만 지속 진행

Fly-Out PhaseOUT
  1. 1

    역방향 스태거 순서 적용

    reverse stagger order
  2. 2

    z값 복귀: 0 → 원래 translateZ

    z: interpolate(0, tz, eased)
  3. 3

    opacity 페이드아웃

    opacity → 0

Patterns

핵심 기술 패턴

단순한 스크롤 애니메이션이 아니라, 3D perspective와 랜덤 스태거를 조합하여 27개 요소가 깊이감 있게 비행하는 패턴입니다. 실무에서 바로 적용할 수 있는 핵심 기술을 정리했습니다.

3D Fly Animation
z축 비행 애니메이션
perspective 500px 컨테이너에서 z:550~1350에서 0으로 수렴한 뒤 다시 발산하는 3단계 플라이 패턴
z: interpolate(tz, 0, eased) opacity: 1 - z / 350
Random Stagger
랜덤 순서 스태거
Math.random()으로 생성한 27개 순서값으로 각 글자·단어의 등장 타이밍을 자연스럽게 분산
staggerOrder = Array(27) .map(() => Math.random())
Dual SplitText
이중 텍스트 분할
heading은 chars로, body는 words로 분할하여 서로 다른 밀도의 3D 플라이 효과 적용
SplitText.create(heading, { type: 'chars' }) SplitText.create(body, { type: 'words' })
Orb Composition
Orb 구성 디자인
main orb 30° 회전 + small orb transformOrigin 250%로 궤도 회전 — 스크롤 progress에 연동
transformOrigin: '250% 250%' rotation: progress * 120
Threshold Calc
스크롤 임계값 계산
섹션 높이 + 뷰포트로 flyInEnd · flyOutStart 임계값을 동적 계산하여 3단계 전환점 결정
flyInEnd = (vh * 1.3) / totalScrollPx flyOutStart = stickyRelease - offset
Depth-Based Opacity
깊이 기반 투명도
z 값이 350 이상이면 opacity가 0으로 수렴하여 먼 거리의 글자가 자연스럽게 사라지는 깊이감 연출
opacity: Math.max(0, 1 - z / 350)

Responsive

반응형 전략

데스크탑 퍼스트로 설계하고 max-xl · max-md 2단계 브레이크포인트만 사용합니다. 3D perspective 효과는 모든 디바이스에서 유지되며, 모바일에서는 세로 스택 레이아웃으로 전환됩니다.

Desktop1280px+
  • 300vh 높이 3D 플라이
  • 좌 45% Orb + 우 55% 텍스트
  • perspective: 500px 3D 효과
  • small orb 궤도 회전
  • chars + words 개별 애니메이션
Tabletmax-xl~1280px
  • 레이아웃 비율 유지
  • 텍스트 크기 축소
  • Orb 크기 vw 반응형
  • 3D 효과 유지
  • 그리드 간격 축소
Mobilemax-md~768px
  • 세로 스택 레이아웃
  • Orb 상단 + 텍스트 하단
  • vw 기반 반응형 크기
  • 3D 효과 유지
  • 그리드 유지 (간격 축소)