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