YumYum 디자인 시스템 — 모션 토큰 v2
냠냠픽업 디자인 시스템 Motion 가이드 작성일: 2026-05-13 버전: v2.0
1. 디자인 원칙
1.1 핵심 컨셉
- UI 모션은 절제, 캐릭터 모션은 풍부 — 두 트랙 분리
- 기본은 300ms ease-out — 자연스럽고 답답하지 않음
- spring/bounce는 캐릭터 전용 — UI에 쓰면 가벼워 보임
- 접근성 고려 —
prefers-reduced-motion지원
1.2 왜 2가지 트랙인가
YumYum은 캐릭터 일러스트가 풍부한 브랜드. 일반 UI 모션을 절제해야 깔끔하고 빠르게 느껴지지만, 캐릭터 모션은 브랜드 차별화 요소라 풍부하게 가야 함. 이 분리가 디자인 일관성의 핵심.
| 트랙 | 특징 | 사용처 |
|---|---|---|
| UI Motion | 짧게 (100-300ms), ease-out 기본 | 버튼, Modal, Toast, 페이지 전환 |
| Character Motion | 길게 (500-1500ms), spring OK | 마스코트, Empty State, Welcome |
2. Duration — 5단계
| Token | Value | 용도 |
|---|---|---|
duration-instant | 100ms | 버튼 press, 즉각 피드백 |
duration-fast | 200ms | Hover, Toast 등장, 작은 전환 |
duration-normal ⭐ | 300ms | 기본값. Modal, Bottom Sheet, 페이지 전환 |
duration-slow | 500ms | 강조 전환, 큰 화면 이동 |
duration-character | 800ms+ | 캐릭터 idle, 반응, 환영 모션 |
2.1 원칙
- 너무 긴 모션은 사용자 답답하게 만듦
- 의사결정: "사용자가 의식할 만한가?"
- 의식 X (UI) → 200-300ms
- 의식 O (캐릭터, 강조) → 500ms+
3. Easing — 5가지 곡선
| Token | Value | 용도 |
|---|---|---|
ease-out ⭐ | cubic-bezier(0, 0, 0.2, 1) | 기본값. 들어오는 모션 (Modal 열기, Toast 등장) |
ease-in | cubic-bezier(0.4, 0, 1, 1) | 나가는 모션 (Modal 닫기, 화면 나가기) |
ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) | 양방향 (페이지 전환) |
ease-linear | linear | 균일한 속도 (Spinner, Progress) |
ease-spring | cubic-bezier(0.34, 1.56, 0.64, 1) | 캐릭터 전용. 통통 튀는 느낌 |
3.1 도착감 vs 출발감
- ease-out = 빠르게 시작 → 천천히 도착 → 들어오는 모션에 자연스러움
- ease-in = 천천히 시작 → 빠르게 떠남 → 나가는 모션에 자연스러움
- ease-in-out = 양쪽 다 부드럽게 → 양방향 전환
4. UI Motion 패턴 — 자주 쓰는 5가지
4.1 Fade In / Out
css
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
animation: fade-in 200ms var(--ease-out);사용처: 등장/사라짐, Toast, Tooltip
4.2 Slide Up (Bottom Sheet)
css
@keyframes slide-up {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
animation: slide-up 300ms var(--ease-out);사용처: Bottom Sheet 열기
4.3 Scale (Button Press)
css
.button:active {
transform: scale(0.98);
transition: transform 100ms var(--ease-out);
}사용처: 버튼/카드 클릭 피드백
4.4 Toast Slide
css
@keyframes toast-enter {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
animation: toast-enter 200ms var(--ease-out);사용처: Toast 등장
4.5 Skeleton / Progress Pulse
css
@keyframes skeleton-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
animation: skeleton-pulse 1500ms var(--ease-in-out) infinite;사용처: Skeleton, Loading indicators
5. Character Motion — 브랜드 차별화 트랙
캐릭터에는 모션 절제 룰이 적용되지 않음. 살아있는 느낌, 따뜻함을 표현.
5.1 5가지 캐릭터 모션 타입
| 타입 | 용도 | Spec |
|---|---|---|
| Idle Bounce | 자연스러운 호흡, 살아있는 느낌 | 2-3s 사이클, translateY ±4px, ease-in-out, infinite |
| Reaction | 사용자 액션 응답 | 1회, spring easing, 500-800ms |
| Empty Companion | Empty State에서 캐릭터가 안내 | idle loop, 조용한 호흡 |
| Welcome | 앱 진입/온보딩 인사 | 1-2초, 한번 강조 후 idle 전환 |
| Loading Character | spinner 대체. 캐릭터가 뭔가 하는 동작 | infinite loop, 1-1.5s 사이클 |
5.2 Idle Bounce 예시
css
@keyframes character-idle {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-4px); }
}
animation: character-idle 2s var(--ease-in-out) infinite;5.3 권장 도구: Lottie
복잡한 캐릭터 모션은 CSS로 만들기 어려움. Lottie(JSON 기반) 사용 권장:
- GIF보다 파일 크기 작음 (10배 이상)
- 벡터라 어떤 사이즈든 깔끔
- After Effects → bodymovin export
- 라이브러리:
lottie-react,lottie-web
6. CSS Variables 구현
css
:root {
/* Duration */
--duration-instant: 100ms;
--duration-fast: 200ms;
--duration-normal: 300ms;
--duration-slow: 500ms;
--duration-character: 800ms;
/* Easing */
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--ease-linear: linear;
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Transition shortcuts */
.transition-default {
transition: all var(--duration-fast) var(--ease-out);
}
.transition-slow {
transition: all var(--duration-normal) var(--ease-out);
}6.1 접근성 — Reduced Motion
css
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}사용자가 OS 설정에서 모션 줄이기 활성화 시 자동 적용.
7. 컴포넌트별 Motion 매핑
| 컴포넌트 | Trigger | Duration | Easing | Property |
|---|---|---|---|---|
| Button | Hover | fast (200ms) | ease-out | background |
| Button | Press | instant (100ms) | ease-out | scale(0.98) |
| Card | Hover | fast (200ms) | ease-out | background, border |
| Modal | Open | normal (300ms) | ease-out | fade + scale |
| Modal | Close | fast (200ms) | ease-in | fade |
| Bottom Sheet | Open | normal (300ms) | ease-out | translateY |
| Bottom Sheet | Close | fast (200ms) | ease-in | translateY |
| Toast | Enter | fast (200ms) | ease-out | translateY + opacity |
| Toast | Exit | fast (200ms) | ease-in | opacity |
| Page transition | Navigate | normal (300ms) | ease-in-out | translateX |
| Tab Bar (active 전환) | Tap | fast (200ms) | ease-out | color, fill |
| Input | Focus | fast (200ms) | ease-out | border, ring |
| Skeleton | Loading | 1500ms loop | ease-in-out | opacity |
| Spinner | Loading | 800ms loop | linear | rotate |
| Character | Idle | 2000ms loop | ease-in-out | translateY |
| Character | Reaction | character (800ms) | spring | scale + rotate |
8. 사용 원칙
8.1 절제 (UI Motion)
- UI는 짧고 자연스럽게
- 한 화면에 동시 모션 2개 이내
- infinite loop는 캐릭터/로딩에만
- spring/bounce는 절대 UI에 쓰지 X
8.2 풍부함 (Character Motion)
- 캐릭터는 항상 미세하게 움직여야 살아있는 느낌
- 사용자 액션마다 캐릭터 반응 가능
- Empty/Loading State에 캐릭터 활용
8.3 접근성
prefers-reduced-motion반드시 지원- 의미 전달은 모션 외에도 가능하게 (색, 텍스트)
- 깜빡임 모션 피하기 (광과민성 발작 위험)
8.4 성능
- transform, opacity 위주 (GPU 가속)
- top/left/width/height 애니메이션 피하기
- will-change는 필요할 때만
9. 기존 vs 신규 비교
| 항목 | 기존 | v2 (신규) |
|---|---|---|
| Duration 정의 | 없음 | 5단계 (100~800ms) |
| Easing 정의 | 없음 | 5가지 곡선 |
| UI vs Character | 구분 없음 | 2가지 트랙 분리 |
| 컴포넌트 매핑 | 없음 | 컴포넌트별 명시 |
| 접근성 | 없음 | prefers-reduced-motion 지원 |
10. 다음 단계
모션까지 정리되면 디자인 시스템의 시각 + 행동 요소가 모두 정의됨. 남은 후속 작업:
- [ ] Accessibility Guidelines — 접근성 체크리스트 (대비, 키보드, 스크린 리더)
- [ ] 실제 화면 디자인 적용 — 만든 시스템으로 핵심 화면 만들기
이 문서는 살아있는 문서입니다. 새로운 모션 패턴 발견 시 함께 업데이트하세요.