Spotify Wrapped 스타일의 AI 코딩 회고
사용자의 AI 코딩 대화 데이터를 분석해 8장의 풀스크린 슬라이드로 보여주는 인터랙티브 경험. 마지막 슬라이드에서 공유 가능한 카드 이미지를 생성해 SNS에 올릴 수 있다.
- 버전 기준: memradar v0.2.12
- 마지막 갱신: 2026-04-19
- 소스 경로:
src/components/wrapped/WrappedView.tsx,src/components/wrapped/slides/* - 이미지 캡처:
html-to-image(toPng)
시각 토큰·모션 어휘는 DESIGN-GUIDE.md §8 참조.
순서는 WrappedView.tsx 의 import 순서와 동일하다. lastSlideIndex = 7.
모든 슬라이드의 큰 타이틀은 font-display 클래스(= --font-display 토큰, 현재 Pretendard Variable)로 통일한다. 인라인 style={{ fontFamily }} 패턴은 금지(2026-05-11 묶음 1B 결정 — 한글 fallback "궁서체" 문제 차단). 자세한 내용은 DESIGN-GUIDE.md §4.1, §4.3 참조.
각 슬라이드의 font-display 사용 요소:
| 슬라이드 | font-display 적용 요소 |
|---|---|
| Cover | "Memradar" 타이틀 (text-5xl md:text-7xl) |
| Intro | 2줄 한글 타이틀 ("당신의 이야기가 / 시작된 날") |
| Prompts | 큰 카운트업 숫자 (AnimatedNumber 래퍼 div, text-7xl md:text-9xl) |
| Model | 모델명 (shortModelName, text-4xl md:text-6xl) |
| Hours | 시간대 라벨 ("Night Owl" 등, text-4xl md:text-5xl) |
| Personality | 성격 타이틀 (personality.title, text-4xl md:text-6xl) |
| Usage | 직업 카테고리 타이틀 (primary.title, text-4xl md:text-6xl) |
| Share | 공유 카드 헤드라인 (personality.title, text-[2.2rem]) |
(orphan — WrappedView 미import. 본 표는 향후 재진입 시 정합성 위해 같이 정리됨: "가장 많이 쓴 도구" 타이틀) |
- 큰 타이틀:
Memradar(font-display토큰 — Pretendard, 타이프라이터 진입) - 서브카피:
당신의 AI 성향은?/What is your AI style? - 요약: "N개의 세션을 바탕으로 당신의 AI 사용 흐름을 읽어볼게요."
- 타이틀 카드 역할. 본 내러티브는 Slide 2(Intro) 부터 시작한다.
구현: src/components/wrapped/slides/CoverSlide.tsx
- Eyebrow:
Your Memradar - 큰 타이틀 (2줄):
당신의 이야기가 / 시작된 날· 영문은The day your / story began(font-display토큰 — Pretendard, 타이프라이터 2단) - 첫 기록 일자:
YYYY년 M월 D일(locale에 따라 ko-KR / en-US, 타이프라이터) - 본문:
그 이후로 N개의 세션을 함께했습니다/N sessions together since then
구현: src/components/wrapped/slides/IntroSlide.tsx
- 총 프롬프트(유저 메시지) 수를
AnimatedNumber로 카운트업 - 보조 카피:
개의 프롬프트를 작성했습니다 - 비유 한 줄:
소설 약 N권 분량(totalPrompts * 50 / 60000, 내림) - 배경 파티클 20개 (deterministic sin-hash)
구현: src/components/wrapped/slides/PromptsSlide.tsx
- 가장 많이 사용한 모델 1종 강조 + 상위 4개 비율 바
- 집계 단위는 응답(response) 수 —
Stats.modelResponses. 세션당 1표가 아니다. Claude 는 distinctrequestId, Codex 는 assistantresponse_item1건이 응답 1건. 원시 라인(프로바이더 로깅 방식 차이)도 병합 블록(모델별 3.76배 편향)도 쓰지 않는다. <synthetic>(중단·한도초과 시스템 응답)은 집계에서 제외된다 — 트랜스크립트 렌더는 유지.- 슬라이드 하단에 단위 영수증 1줄: 총 응답 수 + 서브에이전트 제외 명시. 제외분이 포함분보다 크고, 포함 시 1·2위 격차가 88.7% 우위 → 3.1% 접전으로 바뀐다.
- 모델 성격 라벨 (
getModelLabel):opus계열 → "깊이를 추구하는 사색가"sonnet계열 → "효율과 균형의 달인"haiku계열 → "속도를 사랑하는 스프린터"- 기타 → "다재다능한 코더" (현재
fable·gpt계열이 여기로 떨어진다 — 별도 트랙)
- Wrapped 는 프로바이더 통합 랭킹이다 (전체 코퍼스 요약). 대시보드 도넛은 소스 필터를 따른다.
구현: src/components/wrapped/slides/ModelSlide.tsx
알고리즘: cli/lib/modelAttribution.mjs — sumModelResponses() / src/lib/personality.ts — getModelLabel()
귀속 규칙 전체: docs/goal/model-attribution-per-message.md
- 24시간 활동 분포 막대
- 피크 시간대 라벨 (
getCodingTimeLabel):
| 피크 시각 | 이모지 | 라벨 |
|---|---|---|
| 02:00~05:59 | 🦉 | Night Owl |
| 06:00~09:59 | 🐦 | Early Bird |
| 10:00~13:59 | ☀️ | Morning Warrior |
| 14:00~17:59 | ⚔️ | Afternoon Warrior |
| 18:00~21:59 | 🌆 | Evening Coder |
| 그 외 | 🌙 | Moonlight Coder |
구현: src/components/wrapped/slides/HoursSlide.tsx
알고리즘: src/lib/personality.ts — getCodingTimeLabel()
3축 × 2값 = 8 유형 (src/lib/personality.ts).
| 코드 | 이모지 | 한국어 | 영문 |
|---|---|---|---|
| RDM | 🤿 | 심해 잠수부 | Deep Diver |
| RDS | 🔎 | 코드 감별사 | Code Appraiser |
| RWM | 📚 | 도서관 사서 | Librarian |
| RWS | 🏄 | 트렌드 헌터 | Trend Hunter |
| EDM | ⚒️ | 장인 대장장이 | Master Smith |
| EDS | ⚡ | 번개 해결사 | Lightning Fixer |
| EWM | 🏗️ | 만능 빌더 | All-round Builder |
| EWS | 🌪️ | 카오스 크리에이터 | Chaos Creator |
3축 라벨 (육각 레이더 좌/우 극, 코드 문자):
| 축 | 좌(<0.5) | 우(≥0.5) | 코드 |
|---|---|---|---|
| Style | 탐험가 (Explorer) | 설계자 (Architect) | R / E |
| Scope | 한우물 (Deep) | 유목민 (Wide) | D / W |
| Rhythm | 스프린터 (Sprint) | 마라토너 (Marathon) | S / M |
- Style: 평균 메시지 길이 × 턴 수 × 입출력 토큰 비율
- Scope: 프로젝트 수/주 × 프로젝트 전환율 × 집중도
- Rhythm: 세션 중앙값 × 시간대 엔트로피 × Deep/Quick 세션 비율
3축의 양극을 12시부터 시계방향 6꼭짓점(설계자·유목민·마라토너·탐험가·한우물·스프린터)으로 펼친 육각형 레이더(PersonalityRadar)로 표시한다. 우극 v=value·좌극 v=1−value라 같은 축의 두 극이 지름으로 마주보고(합=1), 우세극(raw ≥ 0.5 + 0.04)은 진하게·균형(±0.04)은 흐리게 렌더된다. 색은 var(--color-*) 토큰이라 Wrapped 스코프(.wrapped-surface)에서 accent가 퍼플로 자동 적응한다. (구 3축 양방향 슬라이더/막대에서 교체됨.) 카드에는 STRENGTHS / HEADS UP 블록이 따라붙는다. 블록 아래에는 면책 캡션 1줄(대화 패턴 기반의 가벼운 성향 추정이에요. 정확한 성격 분석은 아닙니다.)이 표시된다.
구현: src/components/wrapped/slides/PersonalitySlide.tsx
알고리즘: src/lib/personality.ts — computePersonality()
사용자 메시지의 키워드 매칭으로 분류한 9 카테고리 TOP 3. 1위는 대형 이모지로, 2·3위는 칩으로 표시된다.
| 이모지 | 라벨 | 서브 |
|---|---|---|
| 🏭 | 풀스택 기획자 | 기능 뚝딱 제조기 |
| 🚨 | 버그 헌터 | AI 119 신고 전문 |
| 💅 | 리팩터링 전문가 | 못생긴 코드 참을 수 없는 자 |
| 🧐 | 코드 분석가 | "이거 왜 이렇게 짰어?" 전문가 |
| ✍️ | AI 작가 | 글은 AI가 쓰고 이름은 내가 올리고 |
| 🎨 | 아트 디렉터 | "여기 1px 옮겨" 장인 |
| 🚀 | 배포 마스터 | npm publish 중독자 |
| 🧙 | 데이터 엔지니어 | JSON을 금으로 바꾸는 자 |
| 🧪 | QA 엔지니어 | 통과할 때까지 테스트하는 집착러 |
헤드라인은 getUsageHeadline() 규칙:
- TOP1 있음 →
가장 자주 보인 역할은 {카테고리} 쪽이에요 - TOP1 없음 →
당신의 AI 활용 스타일은 아직 탐색 중이에요
슬라이드 하단에는 면책 캡션 1줄(사용자 메시지 패턴 기반의 가벼운 추정이에요. 정확한 분류는 아닙니다.)이 표시된다.
구현: src/components/wrapped/slides/UsageSlide.tsx
알고리즘: src/lib/usageProfile.ts — analyzeUsageTopCategories(), getUsageHeadline()
- 전체 요약 카드 (1장 이미지로 캡처)
- 포함 정보: 이모지, 성격 유형 타이틀/서브,
usageHeadline, 3축 슬라이더, Sessions, Messages, Rhythm(codingLabel), Top Model - 공유 버튼:
- 이미지 저장 —
memradar-code-report.pngPNG 다운로드 - 공유하기 — 플랫폼 모달 (Threads 활성, X · Instagram "개발중" 배지)
- 이미지 저장 —
- 성향 진단 유도: "정밀 진단 해볼래요?" CTA (accent 필 버튼,
Sparkles아이콘) → 페르소나 진단 퀴즈(persona뷰)로 이동.App → WrappedView → ShareSlide의onOpenPersonaQuiz배선 - 대시보드 복귀: 별도의 "전체 보기로 돌아가기" 하단 버튼은 제거됨. 우상단 X, 또는 마지막 슬라이드 도달 2.5초 뒤 빈 곳 클릭 시 뜨는 "전체 분석 화면으로 이동할까요?" 모달로 이동한다 (
WrappedView처리) - 워터마크:
Made in 이더
공유 동작:
- 모바일/PWA:
navigator.canShare({ files })→ 네이티브 공유 시트로 PNG 전달 (navigator.share) - 데스크톱: PNG 를
ClipboardItem으로 클립보드에 복사 → Threads 작성창 탭 오픈 → 사용자가Ctrl/⌘+V - 클립보드 API 실패 시: PNG 다운로드 + Threads 탭 오픈 폴백
구현: src/components/wrapped/slides/ShareSlide.tsx
- 클릭 또는
→/Space: 다음 슬라이드 (인터랙티브 요소·[data-wrapped-control]제외) ←: 이전 슬라이드End: 마지막 슬라이드로 점프Escape: 대시보드 프롬프트가 열려 있으면 닫고, 아니면 Wrapped 종료- 우상단 스킵 버튼: 마지막 슬라이드로 직행
- 우상단
X버튼: Wrapped 즉시 종료 - 마지막 슬라이드 도달 2.5초 후 화면 클릭 시 "대시보드로 이동?" 프롬프트가 열림
- 상단에는 슬라이드 진행률 바, 하단에는 이전/도트/다음 컨트롤
구현: src/components/wrapped/WrappedView.tsx
공용 모션 프리미티브는 src/components/wrapped/slides/SlideLayout.tsx 에 정의.
SlideLayout— 슬라이드 루트(페이드 in/out, 그라디언트 배경, Wrapped 팔레트 주입)FadeInText— 텍스트 페이드 + 16px 슬라이드 업,delay지원AnimatedNumber— 큰 숫자 스프링 등장
상세 값·규칙은 DESIGN-GUIDE.md §6.2 참조.
- 너비:
356px고정, 패딩28px 28px 24px - 배경:
linear-gradient(135deg, #0c0c1a 0%, #10081e 50%, #0c0c1a 100%) - 테두리:
1px solid rgba(123,108,246,0.2), 라운드26px - 캡처:
toPng(cardRef, { pixelRatio: 2, cacheBust: true }) - 파일명:
memradar-code-report.png - 축 색상:
style #7b6cf6,scope #22d3ee,rhythm #f59e0b
Wrapped 는 사용자가 고른 테마와 무관하게 전용 팔레트를 강제 적용한다 (스토리텔링 몰입 유지).
bg #06060e
bg-card #11101d
bg-hover #1b1730
border rgba(255, 255, 255, 0.12)
text #b7b0c9
text-bright #f3efff
accent #7b6cf6 (Axis Style 색)
accent-dim #6254db
정의: src/theme/themePresets.ts, src/index.css (.wrapped-surface)
아직 구현되지 않았거나 보류 중인 아이디어. 도입 전에 UI-UX-PRINCIPLES.md §9 의 "대시보드 vs Code Report 무드 분리" 원칙을 재확인한다.
- Tools 슬라이드 —
slides/ToolsSlide.tsx에 구현체는 남아 있으나 현재WrappedView가 렌더하지 않는다. 재도입 시 순서/필요성 재검토 필요. - Busiest Day 슬라이드 — 달력에서 가장 바빴던 날 하이라이트
- Vocabulary 슬라이드 — 원형 확장 워드 클라우드
- Marathon Session 슬라이드 — 가장 긴 세션 정보
- Cost 슬라이드 — 모델별 누적 비용
- 다국어 내레이션 — 영어 버전 내러티브 톤 정비
초기 기획의 10장 슬라이드 초안은 위 아이디어들을 포함한 것이었다. 현재는 8장 구성(Cover 포함, Tools 제외)이 실제 셀릭된 상태이며, 위 아이디어는 로드맵 ROADMAP.md §2.6 과 연동된다.