@su-record/vibe 2.8.29 → 2.8.31

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.
Files changed (47) hide show
  1. package/README.md +3 -3
  2. package/dist/cli/commands/figma.d.ts +2 -2
  3. package/dist/cli/commands/figma.d.ts.map +1 -1
  4. package/dist/cli/commands/figma.js +3 -7
  5. package/dist/cli/commands/figma.js.map +1 -1
  6. package/dist/cli/commands/skills.d.ts.map +1 -1
  7. package/dist/cli/commands/skills.js +10 -0
  8. package/dist/cli/commands/skills.js.map +1 -1
  9. package/dist/cli/postinstall/codex-agents.d.ts.map +1 -1
  10. package/dist/cli/postinstall/codex-agents.js +3 -2
  11. package/dist/cli/postinstall/codex-agents.js.map +1 -1
  12. package/dist/cli/postinstall/constants.d.ts +2 -0
  13. package/dist/cli/postinstall/constants.d.ts.map +1 -1
  14. package/dist/cli/postinstall/constants.js +14 -0
  15. package/dist/cli/postinstall/constants.js.map +1 -1
  16. package/dist/cli/postinstall/fs-utils.d.ts +4 -0
  17. package/dist/cli/postinstall/fs-utils.d.ts.map +1 -1
  18. package/dist/cli/postinstall/fs-utils.js +11 -0
  19. package/dist/cli/postinstall/fs-utils.js.map +1 -1
  20. package/dist/cli/postinstall/main.d.ts.map +1 -1
  21. package/dist/cli/postinstall/main.js +7 -3
  22. package/dist/cli/postinstall/main.js.map +1 -1
  23. package/dist/infra/lib/figma/api.d.ts +9 -0
  24. package/dist/infra/lib/figma/api.d.ts.map +1 -0
  25. package/dist/infra/lib/figma/api.js +73 -0
  26. package/dist/infra/lib/figma/api.js.map +1 -0
  27. package/dist/infra/lib/figma/extract.d.ts +12 -0
  28. package/dist/infra/lib/figma/extract.d.ts.map +1 -0
  29. package/dist/infra/lib/figma/extract.js +285 -0
  30. package/dist/infra/lib/figma/extract.js.map +1 -0
  31. package/dist/infra/lib/figma/index.d.ts +4 -0
  32. package/dist/infra/lib/figma/index.d.ts.map +1 -0
  33. package/dist/infra/lib/figma/index.js +3 -0
  34. package/dist/infra/lib/figma/index.js.map +1 -0
  35. package/dist/infra/lib/figma/types.d.ts +40 -0
  36. package/dist/infra/lib/figma/types.d.ts.map +1 -0
  37. package/dist/infra/lib/figma/types.js +5 -0
  38. package/dist/infra/lib/figma/types.js.map +1 -0
  39. package/dist/infra/lib/llm-availability.d.ts.map +1 -1
  40. package/dist/infra/lib/llm-availability.js +2 -0
  41. package/dist/infra/lib/llm-availability.js.map +1 -1
  42. package/dist/infra/lib/memory/ReflectionStore.d.ts.map +1 -1
  43. package/dist/infra/lib/memory/ReflectionStore.js +3 -8
  44. package/dist/infra/lib/memory/ReflectionStore.js.map +1 -1
  45. package/package.json +1 -2
  46. package/skills/vibe.figma/SKILL.md +80 -60
  47. package/skills/vibe.figma.extract/SKILL.md +88 -114
@@ -68,14 +68,18 @@ tier: standard
68
68
 
69
69
  ```
70
70
  URL에서 fileKey, nodeId 추출
71
- get_metadata(fileKey, nodeId) → 프레임 목록
72
-
73
- ⚠️ 메타데이터가 클 수 있음 (실전: 291K chars → 파일 저장됨)
74
- 파일 저장 시 Python/Bash로 파싱하여 프레임 목록 추출
75
-
76
- 프레임 분류 (이름 패턴 기반, get_design_context 호출 전에 분류):
77
- SPEC — "기능 정의서", "정책" → get_design_context로 텍스트 추출
78
- CONFIG — "해상도", "브라우저" → get_design_context로 스케일 팩터 계산
71
+ getTree(fileKey, nodeId, depth=2) → 프레임 목록
72
+
73
+ Bash:
74
+ node -e "
75
+ import { getTree } from './dist/infra/lib/figma/index.js';
76
+ const tree = await getTree({ fileKey: '{fileKey}', nodeId: '{nodeId}', depth: 2 });
77
+ console.log(JSON.stringify(tree));
78
+ "
79
+
80
+ 프레임 분류 (name 패턴 기반):
81
+ SPEC — "기능 정의서", "정책" → depth 높여서 텍스트 추출
82
+ CONFIG — "해상도", "브라우저" → 스케일 팩터 계산
79
83
  SHARED — "공통", "GNB", "Footer", "Popup" → 공통 컴포넌트 파악
80
84
  PAGE — "화면설계", "메인 -" → 섹션 목록 + 인터랙션 스펙
81
85
 
@@ -87,8 +91,8 @@ get_metadata(fileKey, nodeId) → 프레임 목록
87
91
  4순위: SHARED (공통 요소, Popup) — 필요 시
88
92
 
89
93
  높이 1500px 이상 프레임:
90
- get_design_context 대신 get_screenshot으로 시각 파악
91
- → 또는 get_metadata로 하위 분할 후 호출
94
+ getScreenshot으로 시각 파악
95
+ → 또는 depth 높여서 하위 분할 조회
92
96
  ```
93
97
 
94
98
  ### 1-2. 레이아웃 + 컴포넌트 구성 (코드 생성)
@@ -224,35 +228,55 @@ SCSS 파일 기본 내용 Write:
224
228
 
225
229
  **각 섹션을 순서대로, 한 섹션을 완전히 완료한 후 다음으로.**
226
230
 
227
- #### a. 참조 코드 획득
231
+ #### a. 노드 트리 + CSS 추출
228
232
 
229
233
  ```
230
- get_design_context(fileKey, 섹션.nodeId)
234
+ Figma REST API로 노드 트리와 CSS 속성을 직접 추출한다.
235
+ MCP 플러그인(get_design_context/get_metadata)은 사용하지 않는다.
236
+
237
+ Bash:
238
+ node -e "
239
+ import { getTree } from './dist/infra/lib/figma/index.js';
240
+ const tree = await getTree({ fileKey: '{fileKey}', nodeId: '{섹션.nodeId}', depth: 10 });
241
+ console.log(JSON.stringify(tree));
242
+ "
231
243
 
232
- 반환:
233
- - const img변수명 = 'URL' (이미지 에셋)
234
- - React+Tailwind JSX (HTML 구조 + CSS 값)
235
- - 스크린샷 (시각 기준점)
236
- - data-name 속성 (레이어 이름: "BG", "Title" 등)
244
+ 반환 (JSON):
245
+ {
246
+ nodeId, name, type, size: {width, height},
247
+ css: { display, flexDirection, gap, fontSize, color, ... },
248
+ text: "텍스트 내용" (TEXT 노드),
249
+ imageRef: "abc123" (이미지 fill),
250
+ children: [...]
251
+ }
237
252
 
238
- 섹션 (높이 1500px+):
239
- get_metadata로 하위 노드 목록 하위 단위로 get_design_context 분할 호출
240
- 타임아웃 시: 1회 재시도 (excludeScreenshot: true) 실패 분할
253
+ CSS는 Figma 노드 속성에서 직접 추출 — Tailwind 역변환 불필요:
254
+ fills background-color effectsbox-shadow, filter
255
+ strokes border stylefont-family, font-size, color
256
+ layoutMode → display:flex itemSpacing → gap
257
+ padding* → padding cornerRadius → border-radius
258
+
259
+ 인스턴스 내부 자식도 depth로 전부 조회 가능 (MCP 한계 해결).
241
260
  ```
242
261
 
243
262
  #### b. 이미지 다운로드 (BLOCKING)
244
263
 
245
264
  ```
246
- 참조 코드의 모든 const img... URL을 추출 다운로드 검증.
247
-
248
- 변수명 → 파일명: imgSnowParticle12 → snow-particle-12.webp
249
- 다운로드: curl -sL "{url}" -o images/{feature}/{파일명}
250
- 검증: ls -la → 모든 파일 존재 + 0byte 아닌지
265
+ 트리에서 imageRef가 있는 노드를 수집Figma API로 다운로드.
251
266
 
252
- 이미지 매핑 생성:
253
- imageMap = { imgTitle: '/images/{feature}/title.webp', ... }
267
+ Bash:
268
+ node -e "
269
+ import { getTree, getImages, collectImageRefs } from './dist/infra/lib/figma/index.js';
270
+ const tree = await getTree({ fileKey: '{fileKey}', nodeId: '{섹션.nodeId}', depth: 10 });
271
+ const refs = collectImageRefs(tree);
272
+ const result = await getImages({
273
+ fileKey: '{fileKey}', imageRefs: refs, outDir: 'images/{feature}/'
274
+ });
275
+ console.log(JSON.stringify(result));
276
+ "
254
277
 
255
- 전부 완료해야 c 단계로 진행. 하나라도 실패 → 코드 생성 금지.
278
+ 검증: result.total = refs.size (누락 0)
279
+ 전부 완료해야 c 단계로 진행.
256
280
  ```
257
281
 
258
282
  #### c. 클래스 매핑 테이블 생성
@@ -262,38 +286,33 @@ SCSS 작성 전에 반드시 매핑 테이블을 먼저 출력한다.
262
286
  이 테이블 없이 SCSS를 작성하지 않는다.
263
287
 
264
288
  1. Phase 1 컴포넌트의 클래스 목록을 Read로 수집
265
- 2. 참조 코드의 data-name + HTML 구조를 분석
289
+ 2. 트리의 name + css 속성을 분석
266
290
  3. 매핑 테이블 출력:
267
291
 
268
- ┌─────────────────────┬──────────────────┬────────────────────────────┐
269
- │ Phase 1 클래스 │ 참조 data-name │ 핵심 Tailwind
270
- ├─────────────────────┼──────────────────┼────────────────────────────┤
271
- │ .kidSection │ (root) │ flex flex-col gap-[32px]
272
- │ .kidBg │ BG │ absolute mix-blend-multiply
273
- │ .kidLoginBtn │ Btn_Login │ border shadow h-[120px]
274
- │ .kidLoginBtnText │ (텍스트 노드) text-[36px] text-white
275
- │ .kidDivider │ Divider │ h-px w-full
276
- │ .kidSteamLink │ steam_account │ text-[24px] font-semibold
277
- │ .kidSteamNote │ (하위 텍스트) text-[20px] #dadce3
278
- └─────────────────────┴──────────────────┴────────────────────────────┘
292
+ ┌─────────────────────┬──────────────────┬────────────────────────────────────┐
293
+ │ Phase 1 클래스 │ 트리 노드 name │ 추출된 CSS
294
+ ├─────────────────────┼──────────────────┼────────────────────────────────────┤
295
+ │ .kidSection │ KID (root) │ flex, column, gap:32px, pad:48px
296
+ │ .kidBg │ BG │ absolute, 720x800
297
+ │ .kidLoginBtn │ Btn_Login │ flex, border, shadow, 640x148
298
+ │ .kidLoginBtnText │ (TEXT 노드) fontSize:36px, color:#fff, w:700
299
+ │ .kidDivider │ Divider │ 640x1
300
+ │ .kidSteamLink │ steam_account │ fontSize:24px, w:600
301
+ │ .kidSteamNote │ (하위 TEXT) fontSize:20px, color:#dadce3
302
+ └─────────────────────┴──────────────────┴────────────────────────────────────┘
279
303
 
280
304
  매핑 기준:
281
- data-name 일치 → 직접 매핑
282
- data-name 없음 → HTML 위치/텍스트 내용으로 판단
305
+ name 일치 → 직접 매핑
306
+ name 없음 → 트리 위치/text 내용으로 판단
283
307
  Phase 1에 없는 요소 → 클래스 신규 추가 (template에도 반영)
284
- 참조 코드에 없는 클래스 → 스타일 없이 유지
308
+ 트리에 없는 클래스 → 스타일 없이 유지
285
309
  ```
286
310
 
287
311
  #### d. SCSS 작성
288
312
 
289
313
  ```
290
- 매핑 테이블의 각 행을 순서대로 CSS로 변환하여 SCSS 작성.
291
- vibe.figma.extract의 Tailwind→CSS 변환표 참조.
292
-
293
- CSS 변수 패턴 처리:
294
- font-[family-name:var(--font/family/pretendard,...)] → fallback 값 사용
295
- text-[length:var(--font/size/heading/24,24px)] → 24px
296
- text-[color:var(--color/grayscale/300,#dadce3)] → #dadce3
314
+ 매핑 테이블의 각 행에 대해, 트리의 css 속성을 SCSS 작성.
315
+ CSS 값은 트리에서 이미 추출되어 있으므로 변환 불필요 — 그대로 사용.
297
316
 
298
317
  scaleFactor 적용:
299
318
  px 값 → × scaleFactor (font-size, padding, margin, gap, width, height, border-radius)
@@ -308,7 +327,7 @@ scaleFactor 적용:
308
327
  styles/{feature}/_tokens.scss
309
328
  → 새로 발견된 색상/폰트/스페이싱 토큰 추가
310
329
 
311
- BG 레이어 패턴 (참조 코드에서 absolute + inset-0 + object-cover):
330
+ BG 레이어 패턴 (트리에서 position:absolute + 이미지 fill):
312
331
  .{section}Bg → position: absolute; inset: 0; z-index: 0;
313
332
  .{section}Content → position: relative; z-index: 1;
314
333
 
@@ -318,14 +337,14 @@ index.scss에 새 섹션 @import 추가.
318
337
  #### e. template 업데이트
319
338
 
320
339
  ```
321
- Phase 1 컴포넌트의 template을 참조 코드 기반으로 리팩토링.
340
+ Phase 1 컴포넌트의 template을 트리 구조 기반으로 리팩토링.
322
341
  script(JSDoc, 인터페이스, 목 데이터, 핸들러)는 보존.
323
342
 
324
- 1. 참조 코드의 HTML 구조를 프로젝트 스택으로 변환:
325
- classNameclass, onClick@click, {조건 && <X/>}v-if 등
343
+ 1. 트리의 HTML 구조를 프로젝트 스택으로 변환:
344
+ FRAME<div>, TEXT<p>/<span>, VECTOR/RECTANGLE with imageRef<img>
326
345
 
327
346
  2. 이미지 경로를 imageMap으로 교체:
328
- src={imgTitle} → src="/images/{feature}/title.webp"
347
+ imageRef "abc123" → src="/images/{feature}/abc123.png"
329
348
 
330
349
  3. BG 레이어 구조 적용:
331
350
  .{section}Bg div (배경) + .{section}Content div (콘텐츠)
@@ -334,7 +353,7 @@ script(JSDoc, 인터페이스, 목 데이터, 핸들러)는 보존.
334
353
  v-for, @click, v-if, $emit 등을 새 구조의 적절한 위치에 배치
335
354
 
336
355
  5. 접근성:
337
- 장식 이미지 → alt="" aria-hidden="true"
356
+ 장식 이미지 (BG 내) → alt="" aria-hidden="true"
338
357
  콘텐츠 이미지 → alt="설명적 텍스트"
339
358
 
340
359
  컴포넌트에 <style> 블록 없음. 스타일은 전부 외부 SCSS.
@@ -344,13 +363,12 @@ script(JSDoc, 인터페이스, 목 데이터, 핸들러)는 보존.
344
363
 
345
364
  ```
346
365
  Grep 체크:
347
- □ "figma.com/api" in 생성 파일 → 0건
348
366
  □ 'src=""' in 컴포넌트 파일 → 0건
349
367
  □ "<style" in 컴포넌트 파일 → 0건
350
368
 
351
369
  Read 체크:
352
370
  □ 외부 SCSS 파일에 font-size, color 존재 (브라우저 기본 스타일 방지)
353
- □ 이미지 파일 수 = const img... 수 (누락 0)
371
+ □ 이미지 파일 수 = imageRef 수 (누락 0)
354
372
 
355
373
  실패 → 수정 → 재검증
356
374
  ```
@@ -373,13 +391,15 @@ Read 체크:
373
391
 
374
392
  ```
375
393
  Grep 체크:
376
- □ "figma.com/api" in 모든 생성 파일 → 0건
377
394
  □ "<style" in components/{feature}/ → 0건
378
395
  □ 'src=""' in components/{feature}/ → 0건
379
396
  □ Glob: images/{feature}/ → 이미지 파일 존재
380
397
 
381
398
  시각 검증:
382
- 섹션: get_screenshot(nodeId) vs dev 서버/preview 비교
399
+ 섹션 스크린샷:
400
+ node -e "import { getScreenshot } from './dist/infra/lib/figma/index.js';
401
+ await getScreenshot({ fileKey: '{fileKey}', nodeId: '{nodeId}', outPath: '/tmp/{section}.png' });"
402
+ → dev 서버/preview와 비교
383
403
  P1 (필수): 이미지 누락, 레이아웃 구조 다름, 텍스트 스타일 미적용
384
404
  P2 (권장): 미세 간격, 미세 색상 차이
385
405
  → P1 수정 → 재검증 (P1=0 될 때까지)
@@ -1,150 +1,124 @@
1
1
  ---
2
2
  name: vibe.figma.extract
3
- description: Figma MCP에서 이미지 다운로드 + CSS 추출
3
+ description: Figma REST API로 노드 트리, CSS, 이미지 추출
4
4
  triggers: []
5
5
  tier: standard
6
6
  ---
7
7
 
8
8
  # vibe.figma.extract — 데이터 추출
9
9
 
10
- `get_design_context` 응답에서 이미지와 CSS 값을 추출하는 절차.
10
+ Figma REST API(`src/infra/lib/figma/`)를 사용하여 노드 트리, CSS, 이미지를 추출.
11
11
 
12
12
  ---
13
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
- ### 파일명 결정
14
+ ## 1. 노드 트리 + CSS 추출
29
15
 
30
16
  ```
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
-
17
+ Bash:
18
+ node -e "
19
+ import { getTree } from './dist/infra/lib/figma/index.js';
20
+ const tree = await getTree({ fileKey: '{fileKey}', nodeId: '{nodeId}', depth: 10 });
21
+ console.log(JSON.stringify(tree));
22
+ "
23
+
24
+ 반환 (FigmaNode JSON):
25
+ {
26
+ nodeId: "641:78152",
27
+ name: "KID",
28
+ type: "INSTANCE",
29
+ size: { width: 720, height: 487 },
30
+ css: { display: "flex", flexDirection: "column", gap: "32px", ... },
31
+ text: "텍스트 내용" (TEXT 노드만),
32
+ imageRef: "abc123" (이미지 fill이 있는 노드만),
33
+ children: [...]
34
+ }
41
35
  ```
42
- for each (변수명, url) in assets:
43
- Bash: curl -sL "{url}" -o public/images/{feature}/{파일명}.webp
44
36
 
45
- 다운로드 검증:
46
- Bash: ls -la public/images/{feature}/
47
- 모든 파일 존재 + 0byte 아닌지 확인
48
- → 실패한 파일 → 재시도 1회
49
- ```
37
+ ### Figma 속성 → CSS 변환표
38
+
39
+ 도구가 자동으로 변환하는 속성:
40
+
41
+ | Figma 속성 | CSS | 스케일 적용 |
42
+ |-----------|-----|-----------|
43
+ | `fills[].color` | `background-color` | ❌ |
44
+ | `fills[].type=IMAGE` | `imageRef` (다운로드 대상) | — |
45
+ | `strokes[].color` + `strokeWeight` | `border` | ✅ (width만) |
46
+ | `effects[].DROP_SHADOW` | `box-shadow` | ✅ (px만) |
47
+ | `effects[].LAYER_BLUR` | `filter: blur()` | ✅ |
48
+ | `effects[].BACKGROUND_BLUR` | `backdrop-filter: blur()` | ✅ |
49
+ | `cornerRadius` | `border-radius` | ✅ |
50
+ | `opacity` | `opacity` | ❌ |
51
+ | `blendMode` | `mix-blend-mode` | ❌ |
52
+ | `style.fontFamily` | `font-family` | ❌ |
53
+ | `style.fontSize` | `font-size` | ✅ |
54
+ | `style.fontWeight` | `font-weight` | ❌ |
55
+ | `style.lineHeightPx` | `line-height` | ❌ (px이지만 상대값으로 취급) |
56
+ | `style.letterSpacing` | `letter-spacing` | ✅ |
57
+ | `style.textAlignHorizontal` | `text-align` | ❌ |
58
+ | `fills[].color` (TEXT) | `color` | ❌ |
59
+ | `characters` | 텍스트 내용 | — |
60
+ | `absoluteBoundingBox.width/height` | `width/height` | ✅ |
61
+ | `layoutMode=VERTICAL` | `display:flex; flex-direction:column` | ❌ |
62
+ | `layoutMode=HORIZONTAL` | `display:flex; flex-direction:row` | ❌ |
63
+ | `primaryAxisAlignItems` | `justify-content` | ❌ |
64
+ | `counterAxisAlignItems` | `align-items` | ❌ |
65
+ | `itemSpacing` | `gap` | ✅ |
66
+ | `padding*` | `padding` | ✅ |
67
+ | `clipsContent` | `overflow: hidden` | ❌ |
68
+ | `layoutPositioning=ABSOLUTE` | `position: absolute` | ❌ |
50
69
 
51
- ### 누락 에셋 처리
70
+ ---
52
71
 
53
- ```
54
- 스크린샷에 보이는 이미지가 참조 코드에 에셋 URL로 없을 때:
72
+ ## 2. 이미지 다운로드
55
73
 
56
- 1. get_metadata(섹션 nodeId)로 하위 노드 목록 확보
57
- 2. 이미지로 의심되는 하위 nodeId에 get_design_context 재호출
58
- → 에셋 URL 발견 시 다운로드
59
- 3. 그래도 없으면 → get_screenshot(해당 nodeId)으로 이미지 직접 저장
60
74
  ```
75
+ 트리에서 imageRef 수집 → Figma API로 다운로드:
61
76
 
62
- ### 이미지 매핑 테이블
63
-
64
- ```
65
- 다운로드 완료 매핑 생성:
77
+ Bash:
78
+ node -e "
79
+ import { getTree, getImages, collectImageRefs } from './dist/infra/lib/figma/index.js';
80
+ const tree = await getTree({ fileKey: '{fileKey}', nodeId: '{nodeId}', depth: 10 });
81
+ const refs = collectImageRefs(tree);
82
+ const result = await getImages({ fileKey: '{fileKey}', imageRefs: refs, outDir: '{outDir}' });
83
+ console.log(JSON.stringify(result));
84
+ "
66
85
 
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
- }
86
+ 반환: { total: N, images: { "imageRef": "/path/to/file.png", ... } }
73
87
 
74
- 매핑은 코드 변환 src={변수명}을 로컬 경로로 교체하는 데 사용.
88
+ 파일명: imageRef 16자 + .png
89
+ 검증: total = refs.size (누락 0), 0byte 파일 없음
75
90
  ```
76
91
 
77
92
  ---
78
93
 
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 변수 패턴
94
+ ## 3. 스크린샷
125
95
 
126
96
  ```
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)]
97
+ Bash:
98
+ node -e "
99
+ import { getScreenshot } from './dist/infra/lib/figma/index.js';
100
+ await getScreenshot({ fileKey: '{fileKey}', nodeId: '{nodeId}', outPath: '{path}' });
101
+ "
131
102
 
132
- var() 안의 fallback 값(24px, #171716)을 사용.
133
- → CSS 변수명은 프로젝트 토큰 네이밍에 참고.
103
+ 시각 검증용. 노드를 PNG로 렌더링하여 저장.
134
104
  ```
135
105
 
136
106
  ---
137
107
 
138
- ## 3. HTML 구조 추출
108
+ ## 4. 노드 구조 참조
139
109
 
140
110
  ```
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에서 처리.
111
+ 트리의 name 속성으로 레이어 용도 파악:
112
+ name="BG" 배경 레이어 (position:absolute, imageRef 포함)
113
+ name="Contents" → 콘텐츠 영역
114
+ name="Title" → 제목
115
+ name="Step1", "Step2" 하위 섹션
116
+ name="Btn_Login" → 버튼
117
+
118
+ type으로 노드 종류 구분:
119
+ FRAME 컨테이너 (div)
120
+ TEXT → 텍스트 (p/span)
121
+ INSTANCE → 컴포넌트 인스턴스 (자식 있음)
122
+ RECTANGLE/VECTOR with imageRef → 이미지 (img)
123
+ GROUP → 그룹 (div)
150
124
  ```