@su-record/vibe 2.8.20 → 2.8.21
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/package.json +1 -1
- package/skills/vibe-figma/SKILL.md +279 -62
- package/skills/vibe-figma-analyze/SKILL.md +4 -338
- package/skills/vibe-figma-codegen/SKILL.md +3 -189
- package/skills/vibe-figma-consolidate/SKILL.md +3 -93
- package/skills/vibe-figma-convert/SKILL.md +284 -0
- package/skills/vibe-figma-extract/SKILL.md +150 -0
- package/skills/vibe-figma-frame/SKILL.md +4 -528
- package/skills/vibe-figma-rules/SKILL.md +3 -456
- package/skills/vibe-figma-style/SKILL.md +3 -207
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vibe-figma-convert
|
|
3
|
+
description: 참조 코드(React+Tailwind) → 프로젝트 코드 + 외부 스타일 파일
|
|
4
|
+
triggers: []
|
|
5
|
+
tier: standard
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# vibe-figma-convert — 코드 변환
|
|
9
|
+
|
|
10
|
+
`get_design_context` 참조 코드를 프로젝트 스택 코드 + 외부 SCSS 파일로 변환.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. 외부 스타일 파일 생성
|
|
15
|
+
|
|
16
|
+
### 변환 예시
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
참조 코드 (React+Tailwind):
|
|
20
|
+
<div className="h-[1280px] relative w-[720px]"> ← 섹션 컨테이너
|
|
21
|
+
<div className="absolute h-[1280px] overflow-clip w-[720px]"> ← BG 레이어
|
|
22
|
+
<img src={img21} className="absolute inset-0 object-cover size-full" />
|
|
23
|
+
</div>
|
|
24
|
+
<div className="absolute flex flex-col items-center top-[130px]"> ← Content
|
|
25
|
+
<div className="h-[174px] w-[620px]"> ← Title 이미지
|
|
26
|
+
<img src={imgTitle} className="absolute inset-0 object-cover size-full" />
|
|
27
|
+
</div>
|
|
28
|
+
<p className="text-[24px] text-white leading-[1.4] text-center"> ← 텍스트
|
|
29
|
+
참여 대상 : PC 유저 (Steam, Kakao)
|
|
30
|
+
</p>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
변환 → styles/{feature}/layout/_hero.scss:
|
|
37
|
+
|
|
38
|
+
@use '../tokens' as t;
|
|
39
|
+
|
|
40
|
+
.heroSection {
|
|
41
|
+
position: relative;
|
|
42
|
+
height: 960px; // 1280 × 0.75
|
|
43
|
+
width: 100%;
|
|
44
|
+
overflow: clip;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.heroBg {
|
|
48
|
+
position: absolute;
|
|
49
|
+
inset: 0;
|
|
50
|
+
z-index: 0;
|
|
51
|
+
img { width: 100%; height: 100%; object-fit: cover; }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.heroContent {
|
|
55
|
+
position: relative;
|
|
56
|
+
z-index: 10;
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
align-items: center;
|
|
60
|
+
padding-top: 98px; // 130 × 0.75
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
변환 → styles/{feature}/components/_hero.scss:
|
|
66
|
+
|
|
67
|
+
@use '../tokens' as t;
|
|
68
|
+
|
|
69
|
+
.heroTitle {
|
|
70
|
+
width: 465px; // 620 × 0.75
|
|
71
|
+
height: 131px; // 174 × 0.75
|
|
72
|
+
img { width: 100%; height: 100%; object-fit: cover; }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.heroParticipation {
|
|
76
|
+
font-size: t.$text-sub; // 24px × 0.75 = 18px
|
|
77
|
+
color: t.$color-white;
|
|
78
|
+
line-height: 1.4;
|
|
79
|
+
text-align: center;
|
|
80
|
+
white-space: nowrap;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### layout vs components 구분
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
layout/ → position, display, flex/grid, width, height, padding, margin,
|
|
88
|
+
gap, overflow, z-index, background-image, inset
|
|
89
|
+
components/ → font-size, font-weight, color, line-height, letter-spacing,
|
|
90
|
+
text-align, border, border-radius, box-shadow, opacity
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### _tokens.scss 업데이트
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
섹션을 처리할 때마다 새로운 고유값을 토큰에 추가:
|
|
97
|
+
|
|
98
|
+
// Colors
|
|
99
|
+
$color-white: #FFFFFF;
|
|
100
|
+
$color-bg-dark: #0A1628;
|
|
101
|
+
$color-heading: #1B3A1D;
|
|
102
|
+
$color-text-body: #333333;
|
|
103
|
+
$color-period-label: #003879;
|
|
104
|
+
$color-grayscale-950: #171716;
|
|
105
|
+
|
|
106
|
+
// Typography (Figma px × scaleFactor)
|
|
107
|
+
$text-hero: 36px; // 48 × 0.75
|
|
108
|
+
$text-sub: 18px; // 24 × 0.75
|
|
109
|
+
$text-body: 16px; // 21 × 0.75
|
|
110
|
+
$text-period: 21px; // 28 × 0.75
|
|
111
|
+
|
|
112
|
+
// Font families
|
|
113
|
+
$font-pretendard: 'Pretendard', sans-serif;
|
|
114
|
+
$font-roboto-condensed: 'Roboto Condensed', sans-serif;
|
|
115
|
+
|
|
116
|
+
// Spacing
|
|
117
|
+
$space-section: 98px; // 130 × 0.75
|
|
118
|
+
$space-content: 18px; // 24 × 0.75
|
|
119
|
+
|
|
120
|
+
// Breakpoints
|
|
121
|
+
$bp-pc: 1024px;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 2. 컴포넌트 파일 변환
|
|
127
|
+
|
|
128
|
+
### Vue / Nuxt
|
|
129
|
+
|
|
130
|
+
```vue
|
|
131
|
+
<template>
|
|
132
|
+
<section class="heroSection">
|
|
133
|
+
<!-- BG Layer -->
|
|
134
|
+
<div class="heroBg">
|
|
135
|
+
<img src="/images/{feature}/bg.webp" alt="" aria-hidden="true" />
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<!-- Content Layer -->
|
|
139
|
+
<div class="heroContent">
|
|
140
|
+
<div class="heroTitle">
|
|
141
|
+
<img src="/images/{feature}/title.webp" alt="추운 겨울, 따뜻한 보상이 펑펑" />
|
|
142
|
+
</div>
|
|
143
|
+
<div class="heroSubTitle">
|
|
144
|
+
<img src="/images/{feature}/sub-title.webp" alt="겨울을 녹일 보상, 지금 PC방에서 획득하세요!" />
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<!-- Period Info (참조 코드 data-name="Period") -->
|
|
148
|
+
<div class="heroPeriod">
|
|
149
|
+
<p class="heroPeriodTarget">참여 대상 : PC 유저 (Steam, Kakao)</p>
|
|
150
|
+
<div class="heroPeriodDetails">
|
|
151
|
+
<div class="heroPeriodItem">
|
|
152
|
+
<p class="heroPeriodLabel">이벤트 기간</p>
|
|
153
|
+
<p class="heroPeriodValue">{{ eventPeriod }}</p>
|
|
154
|
+
</div>
|
|
155
|
+
<div class="heroPeriodItem">
|
|
156
|
+
<p class="heroPeriodLabel">교환/응모 종료일</p>
|
|
157
|
+
<p class="heroPeriodValue">{{ exchangeDeadline }}</p>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<!-- Share Button (참조 코드 data-name="BTN_Share") -->
|
|
164
|
+
<button class="heroShareBtn" @click="handleShare">
|
|
165
|
+
<img src="/images/{feature}/share.webp" alt="공유하기" />
|
|
166
|
+
</button>
|
|
167
|
+
</section>
|
|
168
|
+
</template>
|
|
169
|
+
|
|
170
|
+
<script setup lang="ts">
|
|
171
|
+
/**
|
|
172
|
+
* Hero 섹션 — 키비주얼 + 이벤트 기간 정보
|
|
173
|
+
*
|
|
174
|
+
* [인터랙션] 공유 버튼 클릭 → 공유하기 팝업
|
|
175
|
+
* [상태] 로그인 전/후
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
defineProps<{
|
|
179
|
+
eventPeriod: string
|
|
180
|
+
exchangeDeadline: string
|
|
181
|
+
}>()
|
|
182
|
+
|
|
183
|
+
const emit = defineEmits<{
|
|
184
|
+
share: []
|
|
185
|
+
}>()
|
|
186
|
+
|
|
187
|
+
function handleShare(): void {
|
|
188
|
+
emit('share')
|
|
189
|
+
}
|
|
190
|
+
</script>
|
|
191
|
+
<!-- 스타일: styles/{feature}/layout/_hero.scss + components/_hero.scss -->
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### JSX 변환 규칙 (React+Tailwind → Vue/Nuxt)
|
|
195
|
+
|
|
196
|
+
| React JSX | Vue SFC |
|
|
197
|
+
|-----------|---------|
|
|
198
|
+
| `className="..."` | `class="..."` |
|
|
199
|
+
| `{condition && <X/>}` | `<X v-if="condition" />` |
|
|
200
|
+
| `{items.map(i => <X key={i.id}/>)}` | `<X v-for="i in items" :key="i.id" />` |
|
|
201
|
+
| `onClick={handler}` | `@click="handler"` |
|
|
202
|
+
| `src={변수}` | `src="/images/{feature}/파일.webp"` (imageMap으로 교체) |
|
|
203
|
+
| `style={{ maskImage: ... }}` | `:style="{ maskImage: ... }"` |
|
|
204
|
+
| `<img alt="" />` (장식) | `<img alt="" aria-hidden="true" />` |
|
|
205
|
+
|
|
206
|
+
### JSX 변환 규칙 (React+Tailwind → React/Next.js)
|
|
207
|
+
|
|
208
|
+
| React+Tailwind | React/Next.js + SCSS |
|
|
209
|
+
|----------------|---------------------|
|
|
210
|
+
| `className="text-[48px] font-black"` | `className={styles.heroTitle}` |
|
|
211
|
+
| `<img src={변수}` | `<Image src="/images/{feature}/파일.webp"` |
|
|
212
|
+
| Tailwind 클래스 | CSS Module 또는 외부 SCSS 클래스 |
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 3. 이미지 배치 패턴
|
|
217
|
+
|
|
218
|
+
### 배경 이미지 (참조 코드에서 absolute + inset-0 + object-cover)
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
참조 코드에 이 패턴이 있으면 → 배경 이미지:
|
|
222
|
+
<div className="absolute ...">
|
|
223
|
+
<img src={imgXxx} className="absolute inset-0 object-cover size-full" />
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
→ Multi-Layer 변환:
|
|
227
|
+
.{section}Bg → position: absolute; inset: 0; z-index: 0;
|
|
228
|
+
.{section}Content → position: relative; z-index: 10;
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 콘텐츠 이미지 (참조 코드에서 독립적 img)
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
→ <img src="/images/{feature}/파일.webp" alt="설명" width={스케일적용} height={스케일적용} />
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 장식 이미지 (참조 코드에서 mix-blend, opacity, blur)
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
→ <img ... alt="" aria-hidden="true" /> (접근성: 장식은 비표시)
|
|
241
|
+
→ CSS: mix-blend-mode, opacity, filter: blur() 등 참조 코드 값 그대로
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 4. 반응형 추가 (데스크탑 URL)
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
같은 섹션에 대해 데스크탑 참조 코드 추출 후:
|
|
250
|
+
|
|
251
|
+
같은 값 → 유지
|
|
252
|
+
다른 px 값:
|
|
253
|
+
@include pc {
|
|
254
|
+
.heroSection { height: 1440px; } // 데스크탑 스케일
|
|
255
|
+
}
|
|
256
|
+
또는 clamp(모바일, calc, 데스크탑) 사용
|
|
257
|
+
|
|
258
|
+
다른 배경 이미지:
|
|
259
|
+
.heroBg img { content: url('/images/{feature}/hero-mobile.webp'); }
|
|
260
|
+
@include pc {
|
|
261
|
+
.heroBg img { content: url('/images/{feature}/hero-pc.webp'); }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
다른 레이아웃:
|
|
265
|
+
.heroContent { flex-direction: column; }
|
|
266
|
+
@include pc { .heroContent { flex-direction: row; } }
|
|
267
|
+
|
|
268
|
+
기존 모바일 코드 삭제 금지. @media 또는 mixin으로 추가만.
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 5. Semantic HTML 최소 규칙
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
- 섹션 래퍼: <section>
|
|
277
|
+
- 제목: <h1>~<h6> (순차, 건너뛰기 금지)
|
|
278
|
+
- 텍스트: <p>
|
|
279
|
+
- 버튼: <button> (@click 있으면)
|
|
280
|
+
- 링크: <a> (href 있으면)
|
|
281
|
+
- 리스트: <ul>/<ol> + <li> (반복 패턴)
|
|
282
|
+
- 장식 이미지: alt="" + aria-hidden="true"
|
|
283
|
+
- 콘텐츠 이미지: alt="설명적 텍스트"
|
|
284
|
+
```
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vibe-figma-extract
|
|
3
|
+
description: Figma MCP에서 이미지 다운로드 + CSS 값 추출
|
|
4
|
+
triggers: []
|
|
5
|
+
tier: standard
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# vibe-figma-extract — 데이터 추출
|
|
9
|
+
|
|
10
|
+
`get_design_context` 응답에서 이미지와 CSS 값을 추출하는 절차.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. 이미지 에셋 추출 + 다운로드
|
|
15
|
+
|
|
16
|
+
### URL 추출
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
참조 코드에서 모든 에셋 URL을 수집:
|
|
20
|
+
패턴: const {변수명} = "https://www.figma.com/api/mcp/asset/{uuid}"
|
|
21
|
+
|
|
22
|
+
예:
|
|
23
|
+
const img21 = "https://www.figma.com/api/mcp/asset/76e951df-..."
|
|
24
|
+
const imgTitle = "https://www.figma.com/api/mcp/asset/f97dad41-..."
|
|
25
|
+
const imgSnowParticle12 = "https://www.figma.com/api/mcp/asset/3de2eeed-..."
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 파일명 결정
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
변수명 → kebab-case 파일명:
|
|
32
|
+
img21 → img-21.webp
|
|
33
|
+
imgTitle → title.webp
|
|
34
|
+
imgSnowParticle12 → snow-particle-12.webp
|
|
35
|
+
imgSnowmanItem11 → snowman-item-11.webp
|
|
36
|
+
imgImgBannerStatic → banner-static.webp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 다운로드
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
for each (변수명, url) in assets:
|
|
43
|
+
Bash: curl -sL "{url}" -o public/images/{feature}/{파일명}.webp
|
|
44
|
+
|
|
45
|
+
다운로드 후 검증:
|
|
46
|
+
Bash: ls -la public/images/{feature}/
|
|
47
|
+
→ 모든 파일 존재 + 0byte 아닌지 확인
|
|
48
|
+
→ 실패한 파일 → 재시도 1회
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 누락 에셋 처리
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
스크린샷에 보이는 이미지가 참조 코드에 에셋 URL로 없을 때:
|
|
55
|
+
|
|
56
|
+
1. get_metadata(섹션 nodeId)로 하위 노드 목록 확보
|
|
57
|
+
2. 이미지로 의심되는 하위 nodeId에 get_design_context 재호출
|
|
58
|
+
→ 에셋 URL 발견 시 다운로드
|
|
59
|
+
3. 그래도 없으면 → get_screenshot(해당 nodeId)으로 이미지 직접 저장
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 이미지 매핑 테이블
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
다운로드 완료 후 매핑 생성:
|
|
66
|
+
|
|
67
|
+
imageMap = {
|
|
68
|
+
img21: '/images/{feature}/img-21.webp',
|
|
69
|
+
imgTitle: '/images/{feature}/title.webp',
|
|
70
|
+
imgSnowParticle12: '/images/{feature}/snow-particle-12.webp',
|
|
71
|
+
...
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
이 매핑은 코드 변환 시 src={변수명}을 로컬 경로로 교체하는 데 사용.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 2. CSS 값 추출
|
|
80
|
+
|
|
81
|
+
### Tailwind → CSS 변환표
|
|
82
|
+
|
|
83
|
+
참조 코드의 Tailwind 클래스에서 CSS 속성 + 값을 추출:
|
|
84
|
+
|
|
85
|
+
| Tailwind | CSS | 스케일 적용 |
|
|
86
|
+
|----------|-----|-----------|
|
|
87
|
+
| `text-[48px]` | `font-size: 48px` | ✅ × scaleFactor |
|
|
88
|
+
| `text-[#1B3A1D]` | `color: #1B3A1D` | ❌ |
|
|
89
|
+
| `font-black` | `font-weight: 900` | ❌ |
|
|
90
|
+
| `font-bold` | `font-weight: 700` | ❌ |
|
|
91
|
+
| `font-semibold` | `font-weight: 600` | ❌ |
|
|
92
|
+
| `font-medium` | `font-weight: 500` | ❌ |
|
|
93
|
+
| `leading-[1.4]` | `line-height: 1.4` | ❌ (단위 없음) |
|
|
94
|
+
| `tracking-[-0.36px]` | `letter-spacing: -0.36px` | ✅ |
|
|
95
|
+
| `bg-[#0A1628]` | `background-color: #0A1628` | ❌ |
|
|
96
|
+
| `bg-[rgba(13,40,61,0.5)]` | `background: rgba(13,40,61,0.5)` | ❌ |
|
|
97
|
+
| `pt-[120px]` | `padding-top: 120px` | ✅ |
|
|
98
|
+
| `gap-[24px]` | `gap: 24px` | ✅ |
|
|
99
|
+
| `rounded-[12px]` | `border-radius: 12px` | ✅ |
|
|
100
|
+
| `shadow-[...]` | `box-shadow: ...` | 부분 (px만) |
|
|
101
|
+
| `w-[720px]` | `width: 720px` | ✅ |
|
|
102
|
+
| `h-[1280px]` | `height: 1280px` | ✅ |
|
|
103
|
+
| `opacity-40` | `opacity: 0.4` | ❌ |
|
|
104
|
+
| `blur-[3.5px]` | `filter: blur(3.5px)` | ✅ |
|
|
105
|
+
| `mix-blend-lighten` | `mix-blend-mode: lighten` | ❌ |
|
|
106
|
+
| `mix-blend-multiply` | `mix-blend-mode: multiply` | ❌ |
|
|
107
|
+
| `overflow-clip` | `overflow: clip` | ❌ |
|
|
108
|
+
| `absolute` | `position: absolute` | ❌ |
|
|
109
|
+
| `relative` | `position: relative` | ❌ |
|
|
110
|
+
| `inset-0` | `inset: 0` | ❌ |
|
|
111
|
+
| `flex` | `display: flex` | ❌ |
|
|
112
|
+
| `flex-col` | `flex-direction: column` | ❌ |
|
|
113
|
+
| `items-center` | `align-items: center` | ❌ |
|
|
114
|
+
| `justify-center` | `justify-content: center` | ❌ |
|
|
115
|
+
| `object-cover` | `object-fit: cover` | ❌ |
|
|
116
|
+
| `object-contain` | `object-fit: contain` | ❌ |
|
|
117
|
+
| `whitespace-nowrap` | `white-space: nowrap` | ❌ |
|
|
118
|
+
| `text-center` | `text-align: center` | ❌ |
|
|
119
|
+
| `text-white` | `color: #FFFFFF` | ❌ |
|
|
120
|
+
| `size-full` | `width: 100%; height: 100%` | ❌ |
|
|
121
|
+
| `max-w-none` | `max-width: none` | ❌ |
|
|
122
|
+
| `pointer-events-none` | `pointer-events: none` | ❌ |
|
|
123
|
+
|
|
124
|
+
### CSS 변수 패턴
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
참조 코드에 Figma 디자인 토큰이 CSS 변수로 포함될 수 있음:
|
|
128
|
+
font-[family-name:var(--font/family/pretendard,...)]
|
|
129
|
+
text-[length:var(--font/size/heading/24,24px)]
|
|
130
|
+
text-[color:var(--color/grayscale/950,#171716)]
|
|
131
|
+
|
|
132
|
+
→ var() 안의 fallback 값(24px, #171716)을 사용.
|
|
133
|
+
→ CSS 변수명은 프로젝트 토큰 네이밍에 참고.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 3. HTML 구조 추출
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
참조 코드의 JSX 구조가 HTML 구조.
|
|
142
|
+
data-name 속성으로 레이어 용도 파악:
|
|
143
|
+
data-name="BG" → 배경 레이어
|
|
144
|
+
data-name="Title" → 제목 영역
|
|
145
|
+
data-name="Period" → 기간 정보 영역
|
|
146
|
+
data-name="Light" → 장식 조명
|
|
147
|
+
data-name="BTN_Share" → 공유 버튼
|
|
148
|
+
|
|
149
|
+
구조 변환은 vibe-figma-convert에서 처리.
|
|
150
|
+
```
|