애니메이션 시스템 아키텍트은(는) 무엇을 하나요?
Framer Motion, GSAP, View Transitions API 및 스프링 물리학을 사용하여 고성능의 접근성 있는 애니메이션 시스템을 구축하여 유연한 UI 경험을 제공합니다.
활성화 트리거
활성화 대상: 페이지 전환, 레이아웃 애니메이션, 스크롤 트리거 애니메이션, 마이크로 상호작용, 스프링 물리학, motion.div, gsap.to, View Transition API, 공유 요소 전환, 계단식 목록 애니메이션.
활성화 금지: CSS 전용 호버/포커스 효과 -- css-in-js-architect 사용. Canvas/WebGL 렌더링 -- creative-coding-expert 사용. Lottie 파일 재생 -- 표준 Lottie 통합 사용.
빠른 시작
- 엔진 선택 -- React 선언적 방식에는 Framer Motion, 타임라인 중심 또는 비 React 프로젝트에는 GSAP, 크로스 페이지 네비게이션에는 View Transitions API.
transform과opacity만 애니메이션 -- 이 속성들은 컴포지터 스레드(GPU)에서 실행되어 레이아웃 스래싱을 방지합니다.will-change는 신중하게 사용 -- 애니메이션을 적용할 요소에만 사용하고 완료 후 제거합니다.prefers-reduced-motion존중 -- 요청하는 사용자를 위해 모든 애니메이션을 비활성화하거나 단순화합니다.- DevTools로 프로파일링 -- Performance 탭에서 애니메이션 중 레이아웃 변경 확인.
핵심 기능
| 도메인 | 기술 | 핵심 패턴 |
|---|---|---|
| 선언적 React | Framer Motion 11+, motion 컴포넌트 | 레이아웃 애니메이션, AnimatePresence, variants |
| 타임라인 애니메이션 | GSAP 3.12+, ScrollTrigger | 스크롤 기반 시퀀스, 고정, 스크러빙 |
| 페이지 전환 | View Transitions API, Next.js useViewTransition | 크로스 페이지 공유 요소 전환 |
| 스프링 물리학 | Framer Motion 스프링, react-spring | 자연스러운 이징, 중단 가능한 애니메이션 |
| 마이크로 상호작용 | CSS 전환 + Framer Motion | 버튼 피드백, 호버 상태, 로딩 인디케이터 |
| 스크롤 기반 | CSS animation-timeline: scroll(), GSAP ScrollTrigger | 패럴랙스, 진행률 표시기, 스크롤 시 나타나기 |
아키텍처 패턴
패턴 1: Framer Motion 레이아웃 애니메이션
import { motion, AnimatePresence, LayoutGroup } from 'framer-motion';
function FilterableGrid({ items, filter }: Props) {
const filtered = items.filter(item => item.category === filter);
return (
<LayoutGroup>
<motion.div layout className="grid grid-cols-3 gap-4">
<AnimatePresence mode="popLayout">
{filtered.map(item => (
<motion.div
key={item.id}
layout // 위치 변경 애니메이션
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ type: 'spring', stiffness: 300, damping: 25 }}
>
<Card item={item} />
</motion.div>
))}
</AnimatePresence>
</motion.div>
</LayoutGroup>
);
}
패턴 2: 페이지 탐색을 위한 View Transitions API
// app/components/TransitionLink.tsx
'use client';
import { useRouter } from 'next/navigation';
import { useCallback } from 'react';
export function TransitionLink({ href, children }: { href: string; children: React.ReactNode }) {
const router = useRouter();
const handleClick = useCallback((e: React.MouseEvent) => {
e.preventDefault();
if (!document.startViewTransition) {
router.push(href);
return;
}
document.startViewTransition(() => {
router.push(href);
});
}, [href, router]);
return <a href={href} onClick={handleClick}>{children}</a>;
}
/* view-transition-name을 통한 공유 요소 전환 */
.product-image {
view-transition-name: product-hero;
}
::view-transition-old(product-hero) {
animation: fade-and-scale 0.3s ease-out;
}
::view-transition-new(product-hero) {
animation: fade-and-scale 0.3s ease-in reverse;
}
패턴 3: 축소된 동작 존중
import { useReducedMotion } from 'framer-motion';
function AnimatedComponent() {
const shouldReduce = useReducedMotion();
return (
<motion.div
initial={{ opacity: 0, y: shouldReduce ? 0 : 20 }}
animate={{ opacity: 1, y: 0 }}
transition={shouldReduce
? { duration: 0 }
: { type: 'spring', stiffness: 260, damping: 20 }
}
>
Content
</motion.div>
);
}
┌─ 애니메이션 결정 트리 ───────────────────────┐
│ │
│ prefers-reduced-motion? │
│ ├── 예 → 즉시 투명도 페이드 (움직임 없음) │
│ └── 아니요 → 전체 스프링/변형 애니메이션 │
│ │
│ 무엇을 애니메이션? │
│ ├── transform/opacity → GPU 컴포지터 (좋음) │
│ ├── width/height → 레이아웃 스래싱 (피할 것) │
│ └── box-shadow → 페인트 전용 (허용 가능) │
└───────────────────────────────────────────────────┘
안티 패턴
width,height,top,left애니메이션 -- 매 프레임마다 레이아웃 재계산을 유발합니다. 대신transform: translate/scale을 사용하여 60fps를 유지하세요.- 모든 요소에
will-change사용 -- 너무 많은 레이어를 GPU로 승격시켜 메모리 사용량을 증가시킵니다. 애니메이션을 적용할 요소에만 사용하세요. prefers-reduced-motion무시 -- 움직임에 민감한 사용자는 메스꺼움이나 발작을 경험할 수 있습니다. 항상 이 미디어 쿼리를 확인하고 존중하세요.- 마이크로 상호작용의 애니메이션 지속 시간이 500ms 초과 -- UI가 느리게 느껴집니다. 버튼/호버 피드백은 200ms 미만, 페이지 전환은 400ms 미만으로 유지하세요.
requestAnimationFrame또는 ScrollTrigger 없이 스크롤 중 애니메이션 -- 버벅거림을 유발합니다. 스크롤 기반 애니메이션에는 GSAP ScrollTrigger 또는 CSSanimation-timeline: scroll()을 사용하세요.
품질 체크리스트
- 모든 애니메이션은
transform과opacity를 사용합니다 (컴포지터 친화적 속성) -
prefers-reduced-motion을useReducedMotion또는 CSS 미디어 쿼리로 존중합니다 - 마이크로 상호작용은 200ms 미만, 페이지 전환은 400ms 미만입니다
- 마운트/언마운트 애니메이션에
AnimatePresence를 사용합니다 - 레이아웃 애니메이션은 Framer Motion
layoutprop을 사용합니다 (수동 위치 계산 금지) -
will-change는 애니메이션 중에만 적용되고 완료 후 제거됩니다 - Chrome DevTools Performance 패널에 버벅거림이 없습니다 (16ms 이상의 긴 프레임 없음)
- 애니메이션은 중단 가능합니다 (고정 키프레임 +
ease대신 스프링 물리학 사용) - View Transitions API는 지원되지 않는 브라우저에 대한 폴백이 있습니다
- 스크롤 기반 애니메이션은
animation-timeline또는 ScrollTrigger를 사용합니다 (스크롤 이벤트 리스너 금지)