@su-record/vibe 2.8.11 → 2.8.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/vibe.figma.md +58 -1813
- package/package.json +1 -1
- package/skills/vibe-figma/SKILL.md +121 -0
- package/skills/vibe-figma-analyze/SKILL.md +325 -0
- package/skills/vibe-figma-codegen/SKILL.md +866 -0
- package/skills/vibe-figma-consolidate/SKILL.md +131 -0
- package/skills/vibe-figma-frame/SKILL.md +165 -0
- package/skills/vibe-figma-pipeline/SKILL.md +52 -0
- package/skills/vibe-figma-rules/SKILL.md +259 -0
- package/skills/vibe-figma-style/SKILL.md +583 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vibe-figma-consolidate
|
|
3
|
+
description: Step D — 모바일/PC 스타일 공통화, 컴포넌트 통합, 최종 검증
|
|
4
|
+
triggers: []
|
|
5
|
+
tier: standard
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Skill: vibe-figma-consolidate — Step D: 최종 공통화 리팩토링
|
|
9
|
+
|
|
10
|
+
## D-1. 스타일 공통화
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
1. 모바일/PC에서 동일한 값 → 공통 토큰으로 추출
|
|
14
|
+
2. 중복 CSS/SCSS 규칙 통합
|
|
15
|
+
3. 컴포넌트 내 중복 로직 제거
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 공통화 우선순위
|
|
19
|
+
|
|
20
|
+
| 유형 | 처리 방법 |
|
|
21
|
+
|------|----------|
|
|
22
|
+
| 색상 (모바일/PC 동일) | 공통 CSS custom property로 추출 |
|
|
23
|
+
| 타이포그래피 (동일 scale) | 공통 토큰 유지 |
|
|
24
|
+
| 간격 (다름) | clamp() fluid 토큰으로 변환 |
|
|
25
|
+
| 레이아웃 방향 (다름) | @media 분기 유지 |
|
|
26
|
+
| 컴포넌트 구조 (동일) | 하나의 컴포넌트로 통합 |
|
|
27
|
+
|
|
28
|
+
## D-2. 컴포넌트 통합
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
1. 유사 컴포넌트 (80% rule) → variant prop으로 통합
|
|
32
|
+
2. 중복 sub-component → 공유 컴포넌트로 추출
|
|
33
|
+
3. Fragment/template 활용하여 불필요한 래퍼 제거
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 80% Rule 적용 기준
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
유사도 판단 기준:
|
|
40
|
+
- 레이아웃 구조 동일
|
|
41
|
+
- 색상/크기/텍스트만 다름
|
|
42
|
+
→ 하나의 컴포넌트 + props로 변형
|
|
43
|
+
|
|
44
|
+
- 구조 자체가 다름 (요소 추가/제거, 레이아웃 방향 변경)
|
|
45
|
+
→ 별도 컴포넌트 유지
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
| Stack | 변형 방법 |
|
|
49
|
+
|-------|----------|
|
|
50
|
+
| React | `variant` prop + 조건부 className / style |
|
|
51
|
+
| Vue | `variant` prop + `<slot>` for 커스텀 영역 |
|
|
52
|
+
| Svelte | `variant` prop + `<slot>` |
|
|
53
|
+
| React Native | `variant` prop + StyleSheet 조건 선택 |
|
|
54
|
+
|
|
55
|
+
### 통합 예시 (React)
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
// 통합 전: 별도 컴포넌트 (구조 동일, 색상만 다름)
|
|
59
|
+
<DefaultCard />
|
|
60
|
+
<HighlightCard />
|
|
61
|
+
<CompactCard />
|
|
62
|
+
|
|
63
|
+
// 통합 후: 단일 컴포넌트 + variant
|
|
64
|
+
interface CardProps {
|
|
65
|
+
variant: 'default' | 'highlight' | 'compact';
|
|
66
|
+
title: string;
|
|
67
|
+
children: React.ReactNode;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function Card({ variant, title, children }: CardProps): JSX.Element {
|
|
71
|
+
return (
|
|
72
|
+
<article className={styles[variant]}>
|
|
73
|
+
<h3 className={styles.title}>{title}</h3>
|
|
74
|
+
{children}
|
|
75
|
+
</article>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 불필요한 래퍼 제거
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
// WRONG: 스타일 없는 불필요한 div 래핑
|
|
84
|
+
<div>
|
|
85
|
+
<ComponentA />
|
|
86
|
+
<ComponentB />
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
// CORRECT: Fragment
|
|
90
|
+
<>
|
|
91
|
+
<ComponentA />
|
|
92
|
+
<ComponentB />
|
|
93
|
+
</>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## D-3. 최종 검증 루프
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
🔄 양쪽 뷰포트 동시 검증:
|
|
100
|
+
- 모바일 Figma vs 코드 (mobile viewport)
|
|
101
|
+
- PC Figma vs 코드 (desktop viewport)
|
|
102
|
+
- 양쪽 모두 P1=0, Match Score 95%+
|
|
103
|
+
- 이미지 에셋 전부 정상 표시
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 검증 완료 조건
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
✅ Match Score 95% 이상 (모바일 + 데스크탑 각각)
|
|
110
|
+
✅ P1 불일치 0건
|
|
111
|
+
✅ 모든 이미지 에셋 표시 확인
|
|
112
|
+
✅ 공통 토큰으로 중복 제거 완료
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Model Routing (Step D)
|
|
116
|
+
|
|
117
|
+
| 작업 | 모델 |
|
|
118
|
+
|------|------|
|
|
119
|
+
| 공통화 리팩토링 + 최종 검증 | **Sonnet** |
|
|
120
|
+
| Post — 코드 리뷰 | **gpt-5.3-codex** |
|
|
121
|
+
|
|
122
|
+
### Post — 코드 리뷰 (Codex 설치 시)
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
/codex:review (gpt-5.3-codex)
|
|
126
|
+
생성된 코드의 design fidelity + 코드 품질 크로스 검증
|
|
127
|
+
|
|
128
|
+
Codex 미설치 시 자동 스킵.
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Step D 완료 후 → vibe-figma-pipeline 실행.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vibe-figma-frame
|
|
3
|
+
tier: standard
|
|
4
|
+
description: "디자인 URL → 프레임별 개별 추출 → 스타일/이미지/코드 반영 → 검증 루프. Step B/C 공통."
|
|
5
|
+
triggers: []
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Design Apply (섹션별 정밀 추출 + 코드 반영)
|
|
9
|
+
|
|
10
|
+
디자인 URL 하나를 받아서 **섹션별로 쪼개서 추출**하고, Step A에서 만든 컴포넌트에 스타일/이미지를 채움.
|
|
11
|
+
모바일이든 PC든 동일한 프로세스. 두 번째 호출 시 반응형 레이어만 추가.
|
|
12
|
+
|
|
13
|
+
## 입력
|
|
14
|
+
|
|
15
|
+
- 디자인 Figma URL (전체 페이지)
|
|
16
|
+
- Step A에서 생성된 컴포넌트 파일들
|
|
17
|
+
- 호출 횟수 (첫 번째 = base, 두 번째 이후 = responsive 추가)
|
|
18
|
+
|
|
19
|
+
## Phase 1: 디자인 URL 입력
|
|
20
|
+
|
|
21
|
+
AskUserQuestion (options 사용 금지, 자유 텍스트만):
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
첫 번째 호출:
|
|
25
|
+
question: "🎨 디자인 Figma URL을 입력해주세요."
|
|
26
|
+
→ ⏸️ 응답 대기 (응답 전 다음 진행 금지)
|
|
27
|
+
→ URL 저장 → Phase 2~5 실행
|
|
28
|
+
|
|
29
|
+
검증 완료 후:
|
|
30
|
+
question: "🎨 추가 디자인 URL이 있나요? (없으면 '없음')"
|
|
31
|
+
→ ⏸️ 응답 대기
|
|
32
|
+
→ URL 입력 → responsive 모드로 Phase 2~5 재실행
|
|
33
|
+
→ "없음" → Step C(공통화)로 진행
|
|
34
|
+
|
|
35
|
+
모바일/PC 순서를 강제하지 않음. 어떤 뷰포트든 먼저 입력 가능.
|
|
36
|
+
첫 번째 URL = base 스타일, 추가 URL = 반응형 레이어 추가.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Phase 2: 전체 → 섹션 프레임 매핑
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
1. get_metadata(fileKey, nodeId) → 전체 페이지 하위 프레임 목록
|
|
43
|
+
|
|
44
|
+
2. 프레임 이름으로 Step A 컴포넌트와 매핑:
|
|
45
|
+
| 디자인 프레임 이름 | Step A 컴포넌트 |
|
|
46
|
+
|------------------|----------------|
|
|
47
|
+
| "키 비주얼" / "Hero" / "KV" | HeroSection.vue |
|
|
48
|
+
| "출석" / "Check" / "Mission 01" | DailyCheckInSection.vue |
|
|
49
|
+
| "플레이타임" / "Mission 02" | PlayTimeMissionSection.vue |
|
|
50
|
+
| "교환" / "Exchange" / "Shop" | TokenExchangeSection.vue |
|
|
51
|
+
| "응모" / "Raffle" / "Prize" | TokenRaffleSection.vue |
|
|
52
|
+
| "유의사항" / "Caution" / "Notice" | CautionSection.vue |
|
|
53
|
+
| "GNB" / "Header" / "Nav" | GnbHeader.vue |
|
|
54
|
+
| "Footer" | EventFooter.vue |
|
|
55
|
+
|
|
56
|
+
매핑 방법:
|
|
57
|
+
- 프레임 이름 키워드 매칭
|
|
58
|
+
- 매칭 안 되면 순서(위→아래)로 Step A 섹션과 1:1 대응
|
|
59
|
+
- 그래도 안 되면 get_screenshot으로 비주얼 비교
|
|
60
|
+
|
|
61
|
+
3. 매핑 결과 출력:
|
|
62
|
+
"디자인 프레임 N개 → 컴포넌트 N개 매핑 완료"
|
|
63
|
+
매핑 안 된 프레임이 있으면 사용자에게 확인
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Phase 3: 섹션별 개별 추출
|
|
67
|
+
|
|
68
|
+
**각 매핑된 섹션에 대해 순서대로:**
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
for each (designFrame, component) in mappings:
|
|
72
|
+
|
|
73
|
+
1. get_design_context(fileKey, designFrame.nodeId)
|
|
74
|
+
→ 해당 섹션 전용 코드 + 스크린샷 + 에셋 URL
|
|
75
|
+
|
|
76
|
+
2. 이미지 에셋 다운로드 (BLOCKING):
|
|
77
|
+
→ 응답에서 figma.com/api/mcp/asset/ URL 전부 추출
|
|
78
|
+
→ WebFetch로 다운로드 → static/images/{feature}/ 저장
|
|
79
|
+
→ URL→로컬경로 매핑 테이블에 추가
|
|
80
|
+
|
|
81
|
+
3. 스크린샷 분석:
|
|
82
|
+
→ 레이아웃 (flex/grid 방향, 정렬)
|
|
83
|
+
→ 색상 (배경, 텍스트, 보더)
|
|
84
|
+
→ 타이포 (크기, 굵기, 줄간격)
|
|
85
|
+
→ 간격 (padding, gap, margin)
|
|
86
|
+
→ 배경 이미지 구조 (Multi-Layer: Bg/Overlay/Content)
|
|
87
|
+
|
|
88
|
+
4. component 파일에 반영:
|
|
89
|
+
→ <template> 안의 placeholder를 실제 마크업으로 교체
|
|
90
|
+
→ <style> 블록에 추출한 스타일 작성
|
|
91
|
+
→ 이미지 경로를 로컬 경로로 교체
|
|
92
|
+
→ Step A의 기능 주석과 핸들러는 보존
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Phase 4: 뷰포트 모드에 따른 스타일 적용
|
|
96
|
+
|
|
97
|
+
### 첫 번째 URL (base)
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
- 모든 스타일을 base로 작성 (반응형 미고려)
|
|
101
|
+
- 토큰 파일에 추출한 값 저장
|
|
102
|
+
- 이미지 다운로드 + 로컬 경로 매핑
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 추가 URL (responsive)
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
기존 코드를 수정하지 않고 반응형 레이어만 추가:
|
|
109
|
+
|
|
110
|
+
1. 프레임 width 비교 → 어떤 뷰포트인지 자동 판별
|
|
111
|
+
(base보다 크면 desktop 방향, 작으면 mobile 방향)
|
|
112
|
+
|
|
113
|
+
2. 값이 다른 속성 → clamp() fluid 토큰으로 변환
|
|
114
|
+
- SCSS: figma-fluid($min, $max) 함수 사용
|
|
115
|
+
- CSS: clamp(min, preferred, max)
|
|
116
|
+
|
|
117
|
+
3. 레이아웃 구조가 다른 부분 → @media (min-width: {breakpoint}px)
|
|
118
|
+
- flex-direction 변경
|
|
119
|
+
- grid-template-columns 변경
|
|
120
|
+
- display toggle (baseOnly/responsiveOnly)
|
|
121
|
+
|
|
122
|
+
4. 뷰포트별 배경 이미지 → @media 분기
|
|
123
|
+
.heroBg { background-image: url(base.webp); }
|
|
124
|
+
@media (min-width: {breakpoint}px) { .heroBg { background-image: url(alt.webp); } }
|
|
125
|
+
|
|
126
|
+
5. 추가 이미지 에셋 다운로드 (base와 동일하면 스킵)
|
|
127
|
+
|
|
128
|
+
6. 기존 base 코드/주석/핸들러는 절대 삭제하지 않음
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Phase 5: 검증 루프
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
🔄 Figma 원본 스크린샷 vs 생성된 코드 비교:
|
|
135
|
+
|
|
136
|
+
1. get_screenshot으로 Figma 원본 획득 (이미 Phase 3에서 있음)
|
|
137
|
+
2. 생성된 코드의 렌더링 결과와 비교
|
|
138
|
+
3. 비교 항목:
|
|
139
|
+
- 레이아웃 (배치, 정렬, 간격)
|
|
140
|
+
- 타이포 (크기, 굵기, 색상)
|
|
141
|
+
- 색상 (배경, 텍스트, 보더)
|
|
142
|
+
- 이미지 (배경/에셋 표시 여부)
|
|
143
|
+
- 누락 요소
|
|
144
|
+
|
|
145
|
+
4. Diff Report:
|
|
146
|
+
| 섹션 | 항목 | Figma | 코드 | 심각도 |
|
|
147
|
+
|------|------|-------|------|--------|
|
|
148
|
+
| Hero | 배경 이미지 | 있음 | 누락 | P1 |
|
|
149
|
+
| 출석 | font-size | 24px | 20px | P2 |
|
|
150
|
+
|
|
151
|
+
5. P1 불일치 → 수정 → 재비교 (횟수 제한 없음)
|
|
152
|
+
동일 항목 3회 연속 미해결 → 해당 항목만 사용자 확인 후 계속
|
|
153
|
+
|
|
154
|
+
6. 완료 조건:
|
|
155
|
+
✅ P1 = 0
|
|
156
|
+
✅ 모든 이미지 에셋 표시
|
|
157
|
+
✅ (두 번째 호출 시) 이전 뷰포트도 깨지지 않았는지 재확인
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 참조 스킬
|
|
161
|
+
|
|
162
|
+
코드 생성 시 다음 스킬의 규칙을 적용:
|
|
163
|
+
- `vibe-figma-rules` — 분석/감지 (Phase 1-3)
|
|
164
|
+
- `vibe-figma-style` — 토큰/스타일 (Phase 4, 클래스 네이밍, SCSS)
|
|
165
|
+
- `vibe-figma-codegen` — 마크업/코드 생성 (Phase 5-6, 이미지 패턴, 반응형)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vibe-figma-pipeline
|
|
3
|
+
description: Figma to Code 완료 후 Design Quality Pipeline 안내
|
|
4
|
+
triggers: []
|
|
5
|
+
tier: standard
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Skill: vibe-figma-pipeline — Design Quality Pipeline
|
|
9
|
+
|
|
10
|
+
코드 생성 완료 후, 다음 파이프라인을 사용자에게 제시한다.
|
|
11
|
+
|
|
12
|
+
## Pre-requisite check
|
|
13
|
+
|
|
14
|
+
If `.claude/vibe/design-context.json` does NOT exist:
|
|
15
|
+
```
|
|
16
|
+
⚠️ 디자인 컨텍스트가 없습니다. /design-teach 를 먼저 실행하면
|
|
17
|
+
브랜드, 접근성, 타겟 디바이스에 맞춘 더 정확한 코드를 생성할 수 있습니다.
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick (default recommendation)
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
/design-normalize → /design-audit
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- Normalize: 하드코딩 값 → MASTER.md 토큰으로 치환
|
|
27
|
+
- Audit: A11Y + 성능 + 반응형 + AI Slop 검출
|
|
28
|
+
|
|
29
|
+
## Thorough (recommended for production)
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
/design-normalize → /design-audit → /design-critique → /design-polish
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- + Critique: Nielsen 10 휴리스틱 + 5 페르소나 분석
|
|
36
|
+
- + Polish: 인터랙션 상태 보완 (hover/focus/loading/error)
|
|
37
|
+
|
|
38
|
+
## Output format
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
## 🎨 Design Quality Pipeline
|
|
42
|
+
|
|
43
|
+
생성된 파일: {file list}
|
|
44
|
+
|
|
45
|
+
추천 다음 단계:
|
|
46
|
+
1. /design-normalize — 토큰 정렬 (하드코딩 제거)
|
|
47
|
+
2. /design-audit — 기술 품질 검사
|
|
48
|
+
3. /design-critique — UX 휴리스틱 리뷰
|
|
49
|
+
4. /design-polish — 최종 인터랙션 보완
|
|
50
|
+
|
|
51
|
+
💡 /design-teach 가 아직 설정되지 않았다면 먼저 실행하세요.
|
|
52
|
+
```
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vibe-figma-rules
|
|
3
|
+
description: Figma to Code 분석 및 감지 규칙 — Model Routing, 디자인 분석, 레이어 추출, 스택 감지
|
|
4
|
+
triggers: []
|
|
5
|
+
tier: standard
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Skill: vibe-figma-rules — 분석 및 감지 규칙
|
|
9
|
+
|
|
10
|
+
항상 이 skill을 참조하여 코드를 생성한다.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Model Routing
|
|
15
|
+
|
|
16
|
+
| Step | Claude | GPT (Codex) | 이유 |
|
|
17
|
+
|------|--------|-------------|------|
|
|
18
|
+
| Step A (스토리보드 + 구조) | **Haiku → Sonnet** | — | MCP 추출 → 구조 설계 |
|
|
19
|
+
| Step B (모바일 추출) | **Haiku** | — | MCP + 이미지 다운로드 |
|
|
20
|
+
| Step B (모바일 코드 생성) | **Sonnet** | **gpt-5.3-codex-spark** (병렬) | 섹션별 컴포넌트 생성 |
|
|
21
|
+
| Step B (모바일 검증) | **Sonnet** | — | 이미지 비교 + auto-fix |
|
|
22
|
+
| Step C (PC 추출) | **Haiku** | — | MCP + 이미지 다운로드 |
|
|
23
|
+
| Step C (PC 반응형 반영) | **Sonnet** | — | 기존 코드에 반응형 레이어 추가 |
|
|
24
|
+
| Step C (PC 검증) | **Sonnet** | — | 양쪽 뷰포트 비교 |
|
|
25
|
+
| Step D (공통화) | **Sonnet** | — | 리팩토링 + 최종 검증 |
|
|
26
|
+
| Post (코드 리뷰) | — | **gpt-5.3-codex** | 전체 코드 품질 검증 |
|
|
27
|
+
|
|
28
|
+
### GPT 모델 선택 기준
|
|
29
|
+
|
|
30
|
+
| 모델 | config key | 용도 |
|
|
31
|
+
|------|-----------|------|
|
|
32
|
+
| `gpt-5.4` | `models.gpt` | 아키텍처 판단, 복잡한 추론 |
|
|
33
|
+
| `gpt-5.3-codex` | `models.gptCodex` | 코드 리뷰, 분석 (정확도 우선) |
|
|
34
|
+
| `gpt-5.3-codex-spark` | `models.gptCodexSpark` | 코드 생성 (속도 우선) |
|
|
35
|
+
|
|
36
|
+
`~/.vibe/config.json`의 `models` 에서 오버라이드 가능.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Phase 1: Design Analysis (Image-First)
|
|
41
|
+
|
|
42
|
+
### Single mode
|
|
43
|
+
|
|
44
|
+
Read `figma-output/frame.png` and analyze:
|
|
45
|
+
|
|
46
|
+
| Aspect | What to Extract |
|
|
47
|
+
|--------|-----------------|
|
|
48
|
+
| Layout | Flex/Grid direction, alignment, wrapping |
|
|
49
|
+
| Components | Visual boundaries (cards, buttons, inputs, modals) |
|
|
50
|
+
| Spacing | Padding, margins, gaps between elements |
|
|
51
|
+
| Typography | Font sizes, weights, line heights, hierarchy |
|
|
52
|
+
| Colors | Background, text, border, accent colors |
|
|
53
|
+
| States | Hover/active/disabled indicators if visible |
|
|
54
|
+
| Responsive hints | Breakpoint indicators, fluid vs fixed widths |
|
|
55
|
+
|
|
56
|
+
### Responsive mode
|
|
57
|
+
|
|
58
|
+
Read **ALL** frame images and analyze **side-by-side**:
|
|
59
|
+
|
|
60
|
+
| Aspect | What to Compare |
|
|
61
|
+
|--------|-----------------|
|
|
62
|
+
| Layout shift | Which elements reflow? (e.g., horizontal → vertical stack) |
|
|
63
|
+
| Visibility | Which elements hide/show per viewport? |
|
|
64
|
+
| Typography scale | Font size ratio between viewports |
|
|
65
|
+
| Spacing scale | Padding/gap ratio between viewports |
|
|
66
|
+
| Component shape | Does the component change form? (e.g., drawer → sidebar) |
|
|
67
|
+
| Navigation | Does nav change? (e.g., hamburger ↔ full nav bar) |
|
|
68
|
+
|
|
69
|
+
Build a **viewport diff table**:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
| Element | Mobile (375px) | Desktop (1440px) | Strategy |
|
|
73
|
+
|---------------|------------------------|------------------------|-------------------|
|
|
74
|
+
| Nav | hamburger + drawer | horizontal bar | component swap |
|
|
75
|
+
| Hero title | 24px | 48px | fluid: clamp() |
|
|
76
|
+
| Card grid | 1 column | 3 columns | grid auto-fit |
|
|
77
|
+
| Sidebar | hidden | visible | display toggle |
|
|
78
|
+
| Body text | 14px | 16px | fluid: clamp() |
|
|
79
|
+
| Padding | 16px | 48px | fluid: clamp() |
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Phase 2: Layer Data Extraction
|
|
85
|
+
|
|
86
|
+
### Single mode
|
|
87
|
+
|
|
88
|
+
Read `figma-output/layers.json` and extract:
|
|
89
|
+
|
|
90
|
+
1. **Component hierarchy** — Map nested layers to component tree
|
|
91
|
+
2. **Design tokens** — Colors (fill, stroke), font properties, spacing values, border radius, shadows
|
|
92
|
+
3. **Auto-layout** — Direction, gap, padding (maps directly to flex/grid)
|
|
93
|
+
4. **Constraints** — Fixed vs fluid sizing
|
|
94
|
+
5. **Component instances** — Identify reusable patterns
|
|
95
|
+
6. **Image fills** — Identify layers with `type: "IMAGE"` fills (see Phase 2-A)
|
|
96
|
+
|
|
97
|
+
### Responsive mode
|
|
98
|
+
|
|
99
|
+
Read **ALL** `layers.{N}.json` files and extract **per-viewport**:
|
|
100
|
+
|
|
101
|
+
1. **Per-viewport tokens** — Record exact values for each viewport:
|
|
102
|
+
```
|
|
103
|
+
{ "mobile": { "h1": 24, "body": 14, "padding": 16 },
|
|
104
|
+
"desktop": { "h1": 48, "body": 16, "padding": 48 } }
|
|
105
|
+
```
|
|
106
|
+
2. **Layout differences** — Auto-layout direction changes (e.g., HORIZONTAL → VERTICAL)
|
|
107
|
+
3. **Visibility map** — Which layers exist in one viewport but not the other
|
|
108
|
+
4. **Shared tokens** — Values identical across all viewports (colors, border-radius, shadows are usually shared)
|
|
109
|
+
|
|
110
|
+
### Phase 2-A: Image Fill Classification
|
|
111
|
+
|
|
112
|
+
Figma에서 이미지는 레이어의 `fills` 배열에 `type: "IMAGE"`로 들어옴. 이를 **용도별로 분류**해야 코드에서 올바른 패턴을 생성할 수 있음.
|
|
113
|
+
|
|
114
|
+
#### 감지 방법
|
|
115
|
+
|
|
116
|
+
`layers.json`에서 아래 패턴을 탐색:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
fills: [{ type: "IMAGE", scaleMode: "FILL" | "FIT" | "CROP" | "TILE", imageRef: "..." }]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### 분류 기준
|
|
123
|
+
|
|
124
|
+
| 판별 조건 | 분류 | 코드 패턴 |
|
|
125
|
+
|----------|------|----------|
|
|
126
|
+
| 레이어가 프레임/섹션의 **직계 배경**이고, 위에 텍스트/UI 요소가 겹침 | **Background Image** | `background-image` + `background-size` |
|
|
127
|
+
| 레이어가 독립적이고, 위에 겹치는 요소 없음 | **Content Image** | `<img>` 또는 `<picture>` |
|
|
128
|
+
| 레이어 이름에 `icon`, `logo`, `avatar` 포함 | **Inline Asset** | `<img>` (작은 크기) |
|
|
129
|
+
| 레이어가 반복 패턴(`scaleMode: "TILE"`) | **Pattern/Texture** | `background-image` + `background-repeat` |
|
|
130
|
+
| 레이어가 전체 프레임을 덮고 opacity < 1 또는 blendMode 적용 | **Overlay Image** | `background-image` + overlay `::before`/`::after` |
|
|
131
|
+
|
|
132
|
+
#### 이미지-텍스트 겹침 판별 (Background vs Content)
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
frame의 fills에 IMAGE가 있고, children에 TEXT 레이어가 있으면:
|
|
136
|
+
→ Background Image (텍스트 아래 깔리는 배경)
|
|
137
|
+
|
|
138
|
+
독립 레이어의 fills에 IMAGE가 있고, 형제 레이어와 겹치지 않으면:
|
|
139
|
+
→ Content Image
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### 이미지 소스 추출
|
|
143
|
+
|
|
144
|
+
- `imageRef` 값으로 Figma API의 이미지 렌더링 사용 (`/images/{fileKey}`)
|
|
145
|
+
- 추출된 이미지는 `figma-output/assets/` 디렉토리에 저장
|
|
146
|
+
- 파일명은 레이어 이름 기반: `hero-bg.png`, `product-photo.jpg`
|
|
147
|
+
|
|
148
|
+
### Responsive Scaling Calculation
|
|
149
|
+
|
|
150
|
+
Per-viewport 토큰 쌍에서 clamp() 값을 계산. 공식은 **Phase 4-3** 참조.
|
|
151
|
+
|
|
152
|
+
핵심: Figma 디자인이 2x 스케일(2560px/720px)이므로, 반드시 타겟 해상도(1920px/480px)로 환산 후 clamp를 계산해야 함.
|
|
153
|
+
|
|
154
|
+
**Correction rule**: When image and JSON disagree, **image wins**. The image shows designer intent; JSON may have structural artifacts.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Phase 3: Project Stack Detection + Mode Resolution
|
|
159
|
+
|
|
160
|
+
### 3-1. Detect Stack
|
|
161
|
+
|
|
162
|
+
1. Read `.claude/vibe/config.json` → check `stacks` field
|
|
163
|
+
2. If no config, detect from project files:
|
|
164
|
+
- `package.json` → React, Vue, Svelte, Angular, etc.
|
|
165
|
+
- `tailwind.config.*` → Tailwind CSS
|
|
166
|
+
- `next.config.*` → Next.js
|
|
167
|
+
- `nuxt.config.*` → Nuxt
|
|
168
|
+
- `*.module.css` → CSS Modules pattern
|
|
169
|
+
- `*.scss` / `sass` in deps → SCSS
|
|
170
|
+
- `styled-components` / `@emotion` in deps → CSS-in-JS
|
|
171
|
+
|
|
172
|
+
### 3-2. Load Design Context (Design Skill Integration)
|
|
173
|
+
|
|
174
|
+
Read these files **in order** — later sources override earlier ones:
|
|
175
|
+
|
|
176
|
+
1. **`.claude/vibe/design-context.json`** — brand personality, aesthetic direction, constraints
|
|
177
|
+
- `aesthetic.style` → guides visual weight (minimal vs bold)
|
|
178
|
+
- `aesthetic.colorMood` → warm/cool/vibrant tone for token selection
|
|
179
|
+
- `brand.personality` → preserve brand-expressive elements
|
|
180
|
+
- `constraints.accessibility` → AA or AAA level (affects contrast, focus, ARIA depth)
|
|
181
|
+
- `constraints.devices` → responsive breakpoints priority
|
|
182
|
+
2. **`.claude/vibe/design-system/{project}/MASTER.md`** — authoritative token definitions
|
|
183
|
+
- If MASTER.md exists: **map Figma tokens to MASTER.md tokens first**, only create new tokens for values with no match
|
|
184
|
+
- If no MASTER.md: generate `figma-tokens.css` as standalone token source
|
|
185
|
+
|
|
186
|
+
**Decision rule**: When Figma token ≈ existing MASTER.md token (within 10% color distance or ±2px spacing), **use the existing token** — do not duplicate.
|
|
187
|
+
|
|
188
|
+
### 3-3. Load Breakpoints
|
|
189
|
+
|
|
190
|
+
Breakpoints are loaded from multiple sources in priority order:
|
|
191
|
+
|
|
192
|
+
#### Source Priority
|
|
193
|
+
|
|
194
|
+
| Priority | Source | How |
|
|
195
|
+
|----------|--------|-----|
|
|
196
|
+
| 1 | **Storyboard** | Phase 0-1에서 추출한 `storyboardSpec.breakpoints` |
|
|
197
|
+
| 2 | **`~/.vibe/config.json`** | `figma.breakpoints` — user-customized via `vibe figma breakpoints --set` |
|
|
198
|
+
| 3 | **Project CSS/Tailwind** | Grep `tailwind.config.*` → `theme.screens`, or `@media.*min-width` patterns in codebase |
|
|
199
|
+
| 4 | **Defaults** | Built-in values (breakpoint: 1024px, etc.) |
|
|
200
|
+
|
|
201
|
+
#### Default Breakpoints (built-in)
|
|
202
|
+
|
|
203
|
+
Based on game industry responsive storyboard standards:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
breakpoint: 1024px ← PC↔Mobile boundary (@media min-width)
|
|
207
|
+
pcTarget: 1920px ← PC main target resolution
|
|
208
|
+
mobilePortrait: 480px ← Mobile portrait max width
|
|
209
|
+
mobileMinimum: 360px ← Mobile minimum supported width
|
|
210
|
+
designPc: 2560px ← Figma PC artboard width (design is 2x scale)
|
|
211
|
+
designMobile: 720px ← Figma Mobile artboard width (design is 2x scale)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### How to use in code generation
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
@media breakpoint:
|
|
218
|
+
- Single breakpoint model: @media (min-width: {breakpoint}px)
|
|
219
|
+
- Mobile-first: styles below breakpoint = mobile, above = PC
|
|
220
|
+
|
|
221
|
+
clamp() range:
|
|
222
|
+
- minVw = mobileMinimum (360px) — smallest supported viewport
|
|
223
|
+
- maxVw = pcTarget (1920px) — largest target viewport
|
|
224
|
+
- Values scale linearly between these bounds
|
|
225
|
+
|
|
226
|
+
Design scale factor:
|
|
227
|
+
- PC design at {designPc}px targets {pcTarget}px → scale = pcTarget/designPc
|
|
228
|
+
- Mobile design at {designMobile}px targets {mobilePortrait}px → scale = mobilePortrait/designMobile
|
|
229
|
+
- Apply scale to convert Figma pixel values to target pixel values
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### User customization
|
|
233
|
+
|
|
234
|
+
Users can override any value via CLI:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
vibe figma breakpoints # Show current values
|
|
238
|
+
vibe figma breakpoints --set breakpoint=768 # Change PC↔Mobile boundary
|
|
239
|
+
vibe figma breakpoints --set mobileMinimum=320 # Change mobile minimum
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Stored in `~/.vibe/config.json` → `figma.breakpoints`. Partial overrides merge with defaults.
|
|
243
|
+
|
|
244
|
+
### 3-4. Resolve Generation Mode
|
|
245
|
+
|
|
246
|
+
**Both modes use the project's existing directory structure.** Never create `figma-output/generated/`.
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
if --new flag:
|
|
250
|
+
→ detect project's page/component/style directories (same as default)
|
|
251
|
+
→ generate self-contained token file (no MASTER.md dependency)
|
|
252
|
+
→ components are self-contained (own tokens, no external design system imports)
|
|
253
|
+
→ placed in project's standard directories with feature-named subfolder
|
|
254
|
+
|
|
255
|
+
default (no flag):
|
|
256
|
+
→ scan existing component directories, theme files, token definitions
|
|
257
|
+
→ map output to project's conventions (file location, naming, imports)
|
|
258
|
+
→ add only NEW tokens that don't exist yet
|
|
259
|
+
```
|