@su-record/vibe 2.8.35 → 2.8.37
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/README.md +20 -8
- package/dist/infra/lib/browser/capture.d.ts +26 -0
- package/dist/infra/lib/browser/capture.d.ts.map +1 -0
- package/dist/infra/lib/browser/capture.js +115 -0
- package/dist/infra/lib/browser/capture.js.map +1 -0
- package/dist/infra/lib/browser/compare.d.ts +19 -0
- package/dist/infra/lib/browser/compare.d.ts.map +1 -0
- package/dist/infra/lib/browser/compare.js +133 -0
- package/dist/infra/lib/browser/compare.js.map +1 -0
- package/dist/infra/lib/browser/index.d.ts +5 -0
- package/dist/infra/lib/browser/index.d.ts.map +1 -0
- package/dist/infra/lib/browser/index.js +4 -0
- package/dist/infra/lib/browser/index.js.map +1 -0
- package/dist/infra/lib/browser/launch.d.ts +19 -0
- package/dist/infra/lib/browser/launch.d.ts.map +1 -0
- package/dist/infra/lib/browser/launch.js +59 -0
- package/dist/infra/lib/browser/launch.js.map +1 -0
- package/dist/infra/lib/browser/types.d.ts +103 -0
- package/dist/infra/lib/browser/types.d.ts.map +1 -0
- package/dist/infra/lib/browser/types.js +8 -0
- package/dist/infra/lib/browser/types.js.map +1 -0
- package/hooks/scripts/llm-orchestrate.js +4 -6
- package/package.json +2 -2
- package/skills/vibe.figma/SKILL.md +649 -107
- package/skills/vibe.figma.convert/SKILL.md +139 -161
- package/skills/vibe.figma.extract/SKILL.md +86 -40
|
@@ -1,46 +1,97 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vibe.figma.convert
|
|
3
|
-
description:
|
|
3
|
+
description: 스크린샷 + 재료함 → 프로젝트 코드 + 외부 스타일 파일
|
|
4
4
|
triggers: []
|
|
5
5
|
tier: standard
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# vibe.figma.convert — 코드
|
|
8
|
+
# vibe.figma.convert — 시각 기반 코드 생성
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
**스크린샷을 보고** 코드를 작성한다. Figma 데이터는 정확한 수치/에셋 재료로만 사용.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
❌ Figma 트리를 HTML로 변환 (실패하는 방식)
|
|
14
|
+
✅ 스크린샷을 보고 → 시맨틱 HTML 설계 → 재료함에서 정확한 값 가져다 적용
|
|
15
|
+
```
|
|
12
16
|
|
|
13
17
|
---
|
|
14
18
|
|
|
15
|
-
##
|
|
19
|
+
## 0. 재사용 확인 (코드 작성 전)
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
component-index (/tmp/{feature}/component-index.json) 에서 매칭되는 컴포넌트가 있으면:
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
✅ import하여 사용 (새로 만들지 않음)
|
|
25
|
+
✅ props로 커스터마이즈 (variant, size 등)
|
|
26
|
+
✅ 래퍼 클래스로 위치/크기만 조정
|
|
27
|
+
❌ 기존 컴포넌트 내부 수정
|
|
28
|
+
❌ 90% 유사한데 새로 만들기
|
|
18
29
|
|
|
30
|
+
매칭 안 되면 → 섹션 1 프로세스로 새로 생성 (기존 방식)
|
|
19
31
|
```
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<div className="absolute flex flex-col items-center top-[130px]"> ← Content
|
|
26
|
-
<div className="h-[174px] w-[620px]"> ← Title 이미지
|
|
27
|
-
<img src={imgTitle} className="absolute inset-0 object-cover size-full" />
|
|
28
|
-
</div>
|
|
29
|
-
<p className="text-[24px] text-white leading-[1.4] text-center"> ← 텍스트
|
|
30
|
-
참여 대상 : PC 유저 (Steam, Kakao)
|
|
31
|
-
</p>
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 1. 코드 생성 프로세스
|
|
36
|
+
|
|
34
37
|
```
|
|
38
|
+
입력:
|
|
39
|
+
- 섹션 스크린샷 (정답 사진)
|
|
40
|
+
- 재료함: 이미지 목록, 색상 팔레트, 폰트 목록, 텍스트 콘텐츠, CSS 수치
|
|
41
|
+
|
|
42
|
+
출력:
|
|
43
|
+
- 컴포넌트 파일 (Vue SFC / React TSX)
|
|
44
|
+
- SCSS 파일 (layout/ + components/ + _tokens.scss)
|
|
45
|
+
|
|
46
|
+
프로세스:
|
|
47
|
+
1. 스크린샷을 본다 → "무엇이 보이는가?" 판단
|
|
48
|
+
- 전면 배경 위 콘텐츠? → 히어로 패턴
|
|
49
|
+
- 카드 N개 반복? → 그리드 패턴
|
|
50
|
+
- 탭 + 내용? → 탭 패턴
|
|
51
|
+
- 리스트 + 버튼? → 인터랙티브 리스트 패턴
|
|
52
|
+
|
|
53
|
+
2. 시맨틱 HTML 구조를 설계한다 (Figma 레이어 구조 무시)
|
|
54
|
+
- 스크린샷에서 보이는 시각적 관계를 HTML로 표현
|
|
55
|
+
- <section>, <h2>, <ul>, <button> 등 의미에 맞게
|
|
56
|
+
|
|
57
|
+
3. 재료함에서 정확한 값을 가져온다
|
|
58
|
+
- 이미지: /tmp/{feature}/images/ 에서 해당 파일
|
|
59
|
+
- 색상: tree.json CSS의 정확한 hex/rgba
|
|
60
|
+
- 폰트: 정확한 font-family, size, weight
|
|
61
|
+
- 텍스트: TEXT 노드의 characters 값 그대로
|
|
62
|
+
- 간격: 정확한 padding, gap, margin 값
|
|
63
|
+
|
|
64
|
+
4. 코드를 작성한다
|
|
65
|
+
- 컴포넌트: 스크린샷처럼 보이도록
|
|
66
|
+
- SCSS: 재료함의 정확한 수치 (× scaleFactor)
|
|
67
|
+
- 추정 금지 — 값이 없으면 tree.json에서 다시 찾는다
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
35
71
|
|
|
72
|
+
## 2. 외부 SCSS 파일 구조
|
|
73
|
+
|
|
74
|
+
### layout vs components 구분
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
layout/ → position, display, flex/grid, width, height, padding, margin,
|
|
78
|
+
gap, overflow, z-index, background-image, inset
|
|
79
|
+
components/ → font-size, font-weight, color, line-height, letter-spacing,
|
|
80
|
+
text-align, border, border-radius, box-shadow, opacity
|
|
36
81
|
```
|
|
37
|
-
|
|
82
|
+
|
|
83
|
+
### layout 예시 (스크린샷 기반으로 작성)
|
|
84
|
+
|
|
85
|
+
```scss
|
|
86
|
+
// 스크린샷에서 보이는 구조:
|
|
87
|
+
// - 전면 배경 이미지 위에 중앙 정렬된 콘텐츠
|
|
88
|
+
// 재료함에서 가져온 값: width=720, height=1280 (→ ×0.75)
|
|
38
89
|
|
|
39
90
|
@use '../tokens' as t;
|
|
40
91
|
|
|
41
92
|
.heroSection {
|
|
42
93
|
position: relative;
|
|
43
|
-
height: 960px; // 1280 × 0.75
|
|
94
|
+
height: 960px; // 재료: 1280 × 0.75
|
|
44
95
|
width: 100%;
|
|
45
96
|
overflow: clip;
|
|
46
97
|
}
|
|
@@ -58,129 +109,102 @@ tier: standard
|
|
|
58
109
|
display: flex;
|
|
59
110
|
flex-direction: column;
|
|
60
111
|
align-items: center;
|
|
61
|
-
padding-top: 98px; // 130 × 0.75
|
|
112
|
+
padding-top: 98px; // 재료: 130 × 0.75
|
|
62
113
|
}
|
|
63
114
|
```
|
|
64
115
|
|
|
65
|
-
|
|
66
|
-
|
|
116
|
+
### components 예시
|
|
117
|
+
|
|
118
|
+
```scss
|
|
119
|
+
// 스크린샷에서 보이는 요소:
|
|
120
|
+
// - 큰 타이틀 이미지, 그 아래 흰색 텍스트
|
|
121
|
+
// 재료함: fontSize=24, color=#ffffff, width=620, height=174
|
|
67
122
|
|
|
68
123
|
@use '../tokens' as t;
|
|
69
124
|
|
|
70
125
|
.heroTitle {
|
|
71
|
-
width: 465px; // 620 × 0.75
|
|
72
|
-
height: 131px; // 174 × 0.75
|
|
126
|
+
width: 465px; // 재료: 620 × 0.75
|
|
127
|
+
height: 131px; // 재료: 174 × 0.75
|
|
73
128
|
img { width: 100%; height: 100%; object-fit: cover; }
|
|
74
129
|
}
|
|
75
130
|
|
|
76
|
-
.
|
|
77
|
-
font-size: t.$font-size-md; // 24px × 0.667 = 16px
|
|
78
|
-
color: t.$color-text-primary; //
|
|
131
|
+
.heroText {
|
|
132
|
+
font-size: t.$font-size-md; // 재료: 24px × 0.667 = 16px
|
|
133
|
+
color: t.$color-text-primary; // 재료: #ffffff
|
|
79
134
|
line-height: 1.4;
|
|
80
135
|
text-align: center;
|
|
81
|
-
white-space: nowrap;
|
|
82
136
|
}
|
|
83
137
|
```
|
|
84
138
|
|
|
85
|
-
###
|
|
139
|
+
### _tokens.scss 구조 (기존 토큰 참조 + 새 토큰)
|
|
86
140
|
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
text-align, border, border-radius, box-shadow, opacity
|
|
92
|
-
```
|
|
141
|
+
```scss
|
|
142
|
+
// ─── 기존 토큰 참조 (프로젝트에 이미 있는 경우) ───
|
|
143
|
+
// project-tokens.json 매칭 결과에 따라 @use로 참조
|
|
144
|
+
@use '../../styles/variables' as v;
|
|
93
145
|
|
|
94
|
-
|
|
146
|
+
// ─── 매핑 (기존 토큰 → 피처 시맨틱 별칭) ────────
|
|
147
|
+
$color-bg-primary: v.$color-navy; // 기존 토큰 재사용
|
|
148
|
+
$color-text-primary: v.$color-white; // 기존 토큰 재사용
|
|
95
149
|
|
|
96
|
-
|
|
97
|
-
//
|
|
98
|
-
|
|
150
|
+
// ─── 새 토큰 (매칭 안 된 값만 생성) ─────────────
|
|
151
|
+
// 기존 토큰이 없는 프로젝트에서는 아래처럼 전체 생성 (기존 방식)
|
|
152
|
+
|
|
153
|
+
// ─── Primitive (재료함의 원시 값) ────────────────
|
|
99
154
|
$color-white: #ffffff;
|
|
100
155
|
$color-black: #000000;
|
|
101
156
|
$color-navy-dark: #0a1628;
|
|
102
157
|
$color-navy-medium: #00264a;
|
|
103
158
|
|
|
104
|
-
// Font families
|
|
105
159
|
$font-pretendard: 'Pretendard', sans-serif;
|
|
106
|
-
$font-roboto-condensed: 'Roboto Condensed', sans-serif;
|
|
107
160
|
|
|
108
|
-
//
|
|
109
|
-
$font-size-
|
|
110
|
-
$font-size-
|
|
111
|
-
$font-size-
|
|
112
|
-
$font-size-lg: 19px; // 28 × 0.667
|
|
161
|
+
$font-size-xs: 11px; // 재료: 16 × 0.667
|
|
162
|
+
$font-size-sm: 13px; // 재료: 20 × 0.667
|
|
163
|
+
$font-size-md: 16px; // 재료: 24 × 0.667
|
|
164
|
+
$font-size-lg: 19px; // 재료: 28 × 0.667
|
|
113
165
|
|
|
114
|
-
// Font weights
|
|
115
166
|
$font-weight-regular: 400;
|
|
116
167
|
$font-weight-medium: 500;
|
|
117
168
|
$font-weight-bold: 700;
|
|
118
169
|
|
|
119
|
-
// Spacing (scaled)
|
|
120
170
|
$space-xs: 5px;
|
|
121
171
|
$space-sm: 11px;
|
|
122
172
|
$space-md: 16px;
|
|
123
173
|
$space-lg: 21px;
|
|
124
174
|
|
|
125
175
|
// ─── Semantic (용도별) ────────────────────────
|
|
126
|
-
// Text
|
|
127
176
|
$color-text-primary: $color-white;
|
|
128
177
|
$color-text-secondary: #dadce3;
|
|
129
|
-
$color-text-label: #003879;
|
|
130
|
-
$color-text-link: #419bd3;
|
|
131
|
-
|
|
132
|
-
// Background
|
|
133
178
|
$color-bg-primary: $color-navy-dark;
|
|
134
179
|
$color-bg-section: $color-navy-medium;
|
|
135
|
-
|
|
136
|
-
// Border
|
|
137
180
|
$color-border-primary: #203f6c;
|
|
138
|
-
|
|
139
|
-
// Breakpoint
|
|
140
181
|
$bp-desktop: 1024px;
|
|
141
182
|
|
|
142
|
-
규칙:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### CSS 변수 패턴 처리
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
참조 코드에 Figma 디자인 토큰이 CSS 변수로 포함될 수 있음:
|
|
152
|
-
font-[family-name:var(--font/family/pretendard,...)]
|
|
153
|
-
text-[length:var(--font/size/heading/24,24px)]
|
|
154
|
-
text-[color:var(--color/grayscale/950,#171716)]
|
|
155
|
-
|
|
156
|
-
→ var() 안의 fallback 값(24px, #171716)을 사용.
|
|
157
|
-
→ CSS 변수명은 프로젝트 토큰 네이밍에 참고.
|
|
183
|
+
// 규칙:
|
|
184
|
+
// - primitive: 재료함의 고유 값 (hex, 폰트명, px)
|
|
185
|
+
// - semantic: primitive 참조로 용도별 이름
|
|
186
|
+
// - 같은 값 중복 금지 — 기존 토큰 재사용
|
|
158
187
|
```
|
|
159
188
|
|
|
160
189
|
---
|
|
161
190
|
|
|
162
|
-
##
|
|
191
|
+
## 3. 컴포넌트 작성
|
|
163
192
|
|
|
164
|
-
### Vue / Nuxt
|
|
193
|
+
### Vue / Nuxt 예시
|
|
165
194
|
|
|
166
195
|
```vue
|
|
196
|
+
<!-- 스크린샷 기반: 전면 배경 + 중앙 타이틀 + 기간 정보 + 공유 버튼 -->
|
|
167
197
|
<template>
|
|
168
198
|
<section class="heroSection">
|
|
169
|
-
<!-- BG Layer -->
|
|
170
199
|
<div class="heroBg">
|
|
171
200
|
<img src="/images/{feature}/bg.webp" alt="" aria-hidden="true" />
|
|
172
201
|
</div>
|
|
173
202
|
|
|
174
|
-
<!-- Content Layer -->
|
|
175
203
|
<div class="heroContent">
|
|
176
204
|
<div class="heroTitle">
|
|
177
205
|
<img src="/images/{feature}/title.webp" alt="추운 겨울, 따뜻한 보상이 펑펑" />
|
|
178
206
|
</div>
|
|
179
|
-
<div class="heroSubTitle">
|
|
180
|
-
<img src="/images/{feature}/sub-title.webp" alt="겨울을 녹일 보상, 지금 PC방에서 획득하세요!" />
|
|
181
|
-
</div>
|
|
182
207
|
|
|
183
|
-
<!-- Period Info (참조 코드 data-name="Period") -->
|
|
184
208
|
<div class="heroPeriod">
|
|
185
209
|
<p class="heroPeriodTarget">참여 대상 : PC 유저 (Steam, Kakao)</p>
|
|
186
210
|
<div class="heroPeriodDetails">
|
|
@@ -188,15 +212,10 @@ $bp-desktop: 1024px;
|
|
|
188
212
|
<p class="heroPeriodLabel">이벤트 기간</p>
|
|
189
213
|
<p class="heroPeriodValue">{{ eventPeriod }}</p>
|
|
190
214
|
</div>
|
|
191
|
-
<div class="heroPeriodItem">
|
|
192
|
-
<p class="heroPeriodLabel">교환/응모 종료일</p>
|
|
193
|
-
<p class="heroPeriodValue">{{ exchangeDeadline }}</p>
|
|
194
|
-
</div>
|
|
195
215
|
</div>
|
|
196
216
|
</div>
|
|
197
217
|
</div>
|
|
198
218
|
|
|
199
|
-
<!-- Share Button (참조 코드 data-name="BTN_Share") -->
|
|
200
219
|
<button class="heroShareBtn" @click="handleShare">
|
|
201
220
|
<img src="/images/{feature}/share.webp" alt="공유하기" />
|
|
202
221
|
</button>
|
|
@@ -204,21 +223,11 @@ $bp-desktop: 1024px;
|
|
|
204
223
|
</template>
|
|
205
224
|
|
|
206
225
|
<script setup lang="ts">
|
|
207
|
-
/**
|
|
208
|
-
* Hero 섹션 — 키비주얼 + 이벤트 기간 정보
|
|
209
|
-
*
|
|
210
|
-
* [인터랙션] 공유 버튼 클릭 → 공유하기 팝업
|
|
211
|
-
* [상태] 로그인 전/후
|
|
212
|
-
*/
|
|
213
|
-
|
|
214
226
|
defineProps<{
|
|
215
227
|
eventPeriod: string
|
|
216
|
-
exchangeDeadline: string
|
|
217
228
|
}>()
|
|
218
229
|
|
|
219
|
-
const emit = defineEmits<{
|
|
220
|
-
share: []
|
|
221
|
-
}>()
|
|
230
|
+
const emit = defineEmits<{ share: [] }>()
|
|
222
231
|
|
|
223
232
|
function handleShare(): void {
|
|
224
233
|
emit('share')
|
|
@@ -227,93 +236,62 @@ function handleShare(): void {
|
|
|
227
236
|
<!-- 스타일: styles/{feature}/layout/_hero.scss + components/_hero.scss -->
|
|
228
237
|
```
|
|
229
238
|
|
|
230
|
-
###
|
|
239
|
+
### 스택별 변환 규칙
|
|
231
240
|
|
|
232
|
-
|
|
|
233
|
-
|
|
234
|
-
| `
|
|
235
|
-
| `{condition && <X/>}` |
|
|
236
|
-
| `{items.map(i => <X key={i.id}/>)}` |
|
|
237
|
-
|
|
|
238
|
-
|
|
|
239
|
-
| `style={{ maskImage: ... }}` | `:style="{ maskImage: ... }"` |
|
|
240
|
-
| `<img alt="" />` (장식) | `<img alt="" aria-hidden="true" />` |
|
|
241
|
-
|
|
242
|
-
### JSX 변환 규칙 (React+Tailwind → React/Next.js)
|
|
243
|
-
|
|
244
|
-
| React+Tailwind | React/Next.js + SCSS |
|
|
245
|
-
|----------------|---------------------|
|
|
246
|
-
| `className="text-[48px] font-black"` | `className={styles.heroTitle}` |
|
|
247
|
-
| `<img src={변수}` | `<Image src="/images/{feature}/파일.webp"` |
|
|
248
|
-
| Tailwind 클래스 | CSS Module 또는 외부 SCSS 클래스 |
|
|
241
|
+
| Vue/Nuxt | React/Next.js |
|
|
242
|
+
|----------|---------------|
|
|
243
|
+
| `class="..."` | `className={styles.xxx}` (CSS Module) |
|
|
244
|
+
| `v-if="condition"` | `{condition && <X/>}` |
|
|
245
|
+
| `v-for="i in items" :key="i.id"` | `{items.map(i => <X key={i.id}/>)}` |
|
|
246
|
+
| `@click="handler"` | `onClick={handler}` |
|
|
247
|
+
| `<img src="/images/..."` | `<Image src="/images/..."` |
|
|
249
248
|
|
|
250
249
|
---
|
|
251
250
|
|
|
252
|
-
##
|
|
253
|
-
|
|
254
|
-
### 배경 이미지 (참조 코드에서 absolute + inset-0 + object-cover)
|
|
251
|
+
## 4. 이미지 배치 패턴 (스크린샷에서 판단)
|
|
255
252
|
|
|
256
253
|
```
|
|
257
|
-
|
|
258
|
-
<div className="absolute ...">
|
|
259
|
-
<img src={imgXxx} className="absolute inset-0 object-cover size-full" />
|
|
260
|
-
</div>
|
|
261
|
-
|
|
262
|
-
→ Multi-Layer 변환:
|
|
263
|
-
.{section}Bg → position: absolute; inset: 0; z-index: 0;
|
|
264
|
-
.{section}Content → position: relative; z-index: 10;
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
### 콘텐츠 이미지 (참조 코드에서 독립적 img)
|
|
254
|
+
스크린샷에서 판단하는 패턴:
|
|
268
255
|
|
|
269
|
-
|
|
270
|
-
→
|
|
271
|
-
|
|
256
|
+
배경 이미지 (화면 전체를 덮는 큰 이미지):
|
|
257
|
+
→ absolute + inset-0 + object-cover
|
|
258
|
+
→ .{section}Bg (z-index: 0) + .{section}Content (z-index: 10)
|
|
272
259
|
|
|
273
|
-
|
|
260
|
+
콘텐츠 이미지 (독립적 요소):
|
|
261
|
+
→ <img src="..." alt="설명" /> + 고정 width/height
|
|
274
262
|
|
|
275
|
-
|
|
276
|
-
→ <img ... alt="" aria-hidden="true" />
|
|
277
|
-
→
|
|
263
|
+
장식 이미지 (분위기용, 반투명, 블러):
|
|
264
|
+
→ <img ... alt="" aria-hidden="true" />
|
|
265
|
+
→ mix-blend-mode, opacity 등 재료함 값 적용
|
|
278
266
|
```
|
|
279
267
|
|
|
280
268
|
---
|
|
281
269
|
|
|
282
|
-
##
|
|
270
|
+
## 5. 반응형 추가 (데스크탑 URL)
|
|
283
271
|
|
|
284
272
|
```
|
|
285
|
-
|
|
273
|
+
두 번째 URL의 재료를 확보한 후:
|
|
274
|
+
|
|
275
|
+
기존 모바일 코드 유지 + @media 오버라이드만 추가.
|
|
286
276
|
|
|
287
277
|
같은 값 → 유지
|
|
288
|
-
다른 px
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
다른 배경 이미지:
|
|
295
|
-
.heroBg img { content: url('/images/{feature}/hero-mobile.webp'); }
|
|
296
|
-
@include pc {
|
|
297
|
-
.heroBg img { content: url('/images/{feature}/hero-pc.webp'); }
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
다른 레이아웃:
|
|
301
|
-
.heroContent { flex-direction: column; }
|
|
302
|
-
@include pc { .heroContent { flex-direction: row; } }
|
|
303
|
-
|
|
304
|
-
기존 모바일 코드 삭제 금지. @media 또는 mixin으로 추가만.
|
|
278
|
+
다른 px 값 → @include pc { ... } 오버라이드
|
|
279
|
+
다른 레이아웃 → @include pc { flex-direction: row; }
|
|
280
|
+
다른 배경 이미지 → @include pc { content: url(...) }
|
|
281
|
+
|
|
282
|
+
기존 코드 삭제 금지.
|
|
305
283
|
```
|
|
306
284
|
|
|
307
285
|
---
|
|
308
286
|
|
|
309
|
-
##
|
|
287
|
+
## 6. Semantic HTML 규칙
|
|
310
288
|
|
|
311
289
|
```
|
|
312
290
|
- 섹션 래퍼: <section>
|
|
313
291
|
- 제목: <h1>~<h6> (순차, 건너뛰기 금지)
|
|
314
292
|
- 텍스트: <p>
|
|
315
|
-
- 버튼: <button>
|
|
316
|
-
- 링크: <a>
|
|
293
|
+
- 버튼: <button>
|
|
294
|
+
- 링크: <a>
|
|
317
295
|
- 리스트: <ul>/<ol> + <li> (반복 패턴)
|
|
318
296
|
- 장식 이미지: alt="" + aria-hidden="true"
|
|
319
297
|
- 콘텐츠 이미지: alt="설명적 텍스트"
|
|
@@ -1,22 +1,51 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vibe.figma.extract
|
|
3
|
-
description: Figma REST API로
|
|
3
|
+
description: Figma REST API로 재료 확보 — 스크린샷, 이미지, CSS, 트리, 텍스트
|
|
4
4
|
triggers: []
|
|
5
5
|
tier: standard
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# vibe.figma.extract —
|
|
8
|
+
# vibe.figma.extract — 재료 확보
|
|
9
9
|
|
|
10
|
-
Figma REST API(`src/infra/lib/figma/`)를 사용하여
|
|
10
|
+
Figma REST API(`src/infra/lib/figma/`)를 사용하여 **퍼즐 조립에 필요한 모든 재료**를 추출.
|
|
11
|
+
추출한 데이터는 코드 변환용이 아닌 **재료함(material inventory)**으로 사용된다.
|
|
11
12
|
|
|
12
13
|
---
|
|
13
14
|
|
|
14
|
-
## 1.
|
|
15
|
+
## 1. 스크린샷 — 정답 사진
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
가장 먼저 확보. 이것이 "만들어야 할 결과물"의 기준.
|
|
19
|
+
|
|
20
|
+
전체 스크린샷:
|
|
21
|
+
node "[FIGMA_SCRIPT]" screenshot {fileKey} {nodeId} --out=/tmp/{feature}/full-screenshot.png
|
|
22
|
+
|
|
23
|
+
섹션별 스크린샷 (1depth 자식 프레임 각각):
|
|
24
|
+
node "[FIGMA_SCRIPT]" screenshot {fileKey} {child.nodeId} --out=/tmp/{feature}/sections/{name}.png
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. 이미지 에셋 — 시각 재료
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
트리에서 imageRef 수집 → Figma API로 다운로드:
|
|
33
|
+
|
|
34
|
+
Bash:
|
|
35
|
+
node "[FIGMA_SCRIPT]" images {fileKey} {nodeId} --out=/tmp/{feature}/images/ --depth=10
|
|
36
|
+
|
|
37
|
+
반환: { total: N, images: { "imageRef": "/path/to/file.png", ... } }
|
|
38
|
+
|
|
39
|
+
검증: total = refs.size (누락 0), 0byte 파일 없음
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 3. 노드 트리 + CSS — 수치 재료
|
|
15
45
|
|
|
16
46
|
```
|
|
17
47
|
Bash:
|
|
18
|
-
|
|
19
|
-
node "[FIGMA_SCRIPT]" tree {fileKey} {nodeId} --depth=10
|
|
48
|
+
node "[FIGMA_SCRIPT]" tree {fileKey} {nodeId} --depth=10
|
|
20
49
|
|
|
21
50
|
반환 (FigmaNode JSON):
|
|
22
51
|
{
|
|
@@ -29,11 +58,18 @@ node "[FIGMA_SCRIPT]" tree {fileKey} {nodeId} --depth=10
|
|
|
29
58
|
imageRef: "abc123" (이미지 fill이 있는 노드만),
|
|
30
59
|
children: [...]
|
|
31
60
|
}
|
|
61
|
+
|
|
62
|
+
⚠️ 주의: 이 트리는 HTML 구조로 변환하지 않는다.
|
|
63
|
+
용도는 오직:
|
|
64
|
+
- 정확한 CSS 수치 참조 (색상, 크기, 간격)
|
|
65
|
+
- 텍스트 콘텐츠 추출
|
|
66
|
+
- 이미지 참조 매핑
|
|
67
|
+
- 디자인 토큰 추출
|
|
32
68
|
```
|
|
33
69
|
|
|
34
70
|
### Figma 속성 → CSS 변환표
|
|
35
71
|
|
|
36
|
-
도구가 자동으로 변환하는
|
|
72
|
+
도구가 자동으로 변환하는 속성 (재료로 활용):
|
|
37
73
|
|
|
38
74
|
| Figma 속성 | CSS | 스케일 적용 |
|
|
39
75
|
|-----------|-----|-----------|
|
|
@@ -49,7 +85,7 @@ node "[FIGMA_SCRIPT]" tree {fileKey} {nodeId} --depth=10
|
|
|
49
85
|
| `style.fontFamily` | `font-family` | ❌ |
|
|
50
86
|
| `style.fontSize` | `font-size` | ✅ |
|
|
51
87
|
| `style.fontWeight` | `font-weight` | ❌ |
|
|
52
|
-
| `style.lineHeightPx` | `line-height` | ❌
|
|
88
|
+
| `style.lineHeightPx` | `line-height` | ❌ |
|
|
53
89
|
| `style.letterSpacing` | `letter-spacing` | ✅ |
|
|
54
90
|
| `style.textAlignHorizontal` | `text-align` | ❌ |
|
|
55
91
|
| `fills[].color` (TEXT) | `color` | ❌ |
|
|
@@ -66,47 +102,57 @@ node "[FIGMA_SCRIPT]" tree {fileKey} {nodeId} --depth=10
|
|
|
66
102
|
|
|
67
103
|
---
|
|
68
104
|
|
|
69
|
-
##
|
|
105
|
+
## 4. 재료함 정리 (material-inventory)
|
|
70
106
|
|
|
71
107
|
```
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
108
|
+
추출 완료 후 재료를 카테고리별로 정리:
|
|
109
|
+
|
|
110
|
+
이미지 목록:
|
|
111
|
+
파일명 | 크기 | 용도 추정
|
|
112
|
+
hero-bg.png | 720×1280 | 배경 (큰 사이즈, BG 레이어)
|
|
113
|
+
title.png | 620×174 | 타이틀 이미지
|
|
114
|
+
btn-share.png | 48×48 | 아이콘 (작은 사이즈)
|
|
115
|
+
|
|
116
|
+
색상 팔레트 (tree.json에서 고유값 추출 + 토큰 매핑 힌트):
|
|
117
|
+
#0a1628, #00264a, #ffffff, #dadce3, #003879, #419bd3, ...
|
|
118
|
+
|
|
119
|
+
토큰 매핑 테이블 (project-tokens.json 존재 시):
|
|
120
|
+
| Figma 값 | 기존 토큰 | 상태 |
|
|
121
|
+
|----------|-----------|------|
|
|
122
|
+
| #0a1628 | $color-navy | ✅ 재사용 |
|
|
123
|
+
| #ffd700 | — | 🆕 생성 |
|
|
124
|
+
| #3b82f6 | $color-primary | ✅ 재사용 |
|
|
125
|
+
|
|
126
|
+
폰트 목록:
|
|
127
|
+
Pretendard: 400/500/700, 16px~48px
|
|
128
|
+
Roboto Condensed: 700, 24px~36px
|
|
129
|
+
|
|
130
|
+
텍스트 콘텐츠 (모든 TEXT 노드):
|
|
131
|
+
"겨울 이벤트", "12.1 ~ 12.31", "참여 대상 : PC 유저", ...
|
|
132
|
+
|
|
133
|
+
간격 패턴 (빈도 높은 값):
|
|
134
|
+
gap: 8px, 16px, 24px, 32px
|
|
135
|
+
padding: 16px, 24px, 32px
|
|
81
136
|
```
|
|
82
137
|
|
|
83
138
|
---
|
|
84
139
|
|
|
85
|
-
##
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
Bash:
|
|
89
|
-
node "[FIGMA_SCRIPT]" screenshot {fileKey} {nodeId} --out={path}
|
|
140
|
+
## 5. 노드 참조 (보조)
|
|
90
141
|
|
|
91
|
-
시각 검증용. 노드를 PNG로 렌더링하여 저장.
|
|
92
142
|
```
|
|
143
|
+
트리의 name/type은 재료 분류에만 사용:
|
|
93
144
|
|
|
94
|
-
|
|
145
|
+
name 패턴 → 용도 힌트:
|
|
146
|
+
"BG" → 배경 이미지 (스크린샷에서 확인)
|
|
147
|
+
"Title", "Txt_*" → 텍스트 영역
|
|
148
|
+
"Btn_*", "CTA" → 버튼/인터랙티브
|
|
149
|
+
"Icon_*" → 아이콘
|
|
150
|
+
"Step1", "Item_*" → 반복 요소
|
|
95
151
|
|
|
96
|
-
|
|
152
|
+
type → 재료 종류:
|
|
153
|
+
TEXT → 텍스트 콘텐츠 제공
|
|
154
|
+
RECTANGLE/VECTOR + imageRef → 다운로드 대상 이미지
|
|
155
|
+
INSTANCE → 반복 사용 가능성 (컴포넌트 후보)
|
|
97
156
|
|
|
98
|
-
|
|
99
|
-
트리의 name 속성으로 레이어 용도 파악:
|
|
100
|
-
name="BG" → 배경 레이어 (position:absolute, imageRef 포함)
|
|
101
|
-
name="Contents" → 콘텐츠 영역
|
|
102
|
-
name="Title" → 제목
|
|
103
|
-
name="Step1", "Step2" → 하위 섹션
|
|
104
|
-
name="Btn_Login" → 버튼
|
|
105
|
-
|
|
106
|
-
type으로 노드 종류 구분:
|
|
107
|
-
FRAME → 컨테이너 (div)
|
|
108
|
-
TEXT → 텍스트 (p/span)
|
|
109
|
-
INSTANCE → 컴포넌트 인스턴스 (자식 있음)
|
|
110
|
-
RECTANGLE/VECTOR with imageRef → 이미지 (img)
|
|
111
|
-
GROUP → 그룹 (div)
|
|
157
|
+
⚠️ 이 정보로 HTML을 생성하지 않는다. 스크린샷을 보고 판단한다.
|
|
112
158
|
```
|