@su-record/vibe 2.8.30 → 2.8.32
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 +3 -3
- package/dist/cli/commands/figma.d.ts +2 -2
- package/dist/cli/commands/figma.d.ts.map +1 -1
- package/dist/cli/commands/figma.js +3 -7
- package/dist/cli/commands/figma.js.map +1 -1
- package/dist/cli/commands/skills.d.ts.map +1 -1
- package/dist/cli/commands/skills.js +10 -0
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/infra/lib/figma/api.d.ts +9 -0
- package/dist/infra/lib/figma/api.d.ts.map +1 -0
- package/dist/infra/lib/figma/api.js +73 -0
- package/dist/infra/lib/figma/api.js.map +1 -0
- package/dist/infra/lib/figma/extract.d.ts +12 -0
- package/dist/infra/lib/figma/extract.d.ts.map +1 -0
- package/dist/infra/lib/figma/extract.js +285 -0
- package/dist/infra/lib/figma/extract.js.map +1 -0
- package/dist/infra/lib/figma/index.d.ts +4 -0
- package/dist/infra/lib/figma/index.d.ts.map +1 -0
- package/dist/infra/lib/figma/index.js +3 -0
- package/dist/infra/lib/figma/index.js.map +1 -0
- package/dist/infra/lib/figma/types.d.ts +40 -0
- package/dist/infra/lib/figma/types.d.ts.map +1 -0
- package/dist/infra/lib/figma/types.js +5 -0
- package/dist/infra/lib/figma/types.js.map +1 -0
- package/dist/infra/lib/llm-availability.d.ts.map +1 -1
- package/dist/infra/lib/llm-availability.js +2 -0
- package/dist/infra/lib/llm-availability.js.map +1 -1
- package/dist/infra/lib/memory/ReflectionStore.d.ts.map +1 -1
- package/dist/infra/lib/memory/ReflectionStore.js +3 -8
- package/dist/infra/lib/memory/ReflectionStore.js.map +1 -1
- package/hooks/scripts/figma-extract.js +225 -0
- package/package.json +1 -2
- package/skills/vibe.figma/SKILL.md +68 -60
- package/skills/vibe.figma.extract/SKILL.md +76 -114
|
@@ -1,150 +1,112 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vibe.figma.extract
|
|
3
|
-
description: Figma
|
|
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
|
-
`
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
17
|
+
Bash:
|
|
18
|
+
# [FIGMA_SCRIPT] = ~/.vibe/hooks/scripts/figma-extract.js
|
|
19
|
+
node "[FIGMA_SCRIPT]" tree {fileKey} {nodeId} --depth=10
|
|
20
|
+
|
|
21
|
+
반환 (FigmaNode JSON):
|
|
22
|
+
{
|
|
23
|
+
nodeId: "641:78152",
|
|
24
|
+
name: "KID",
|
|
25
|
+
type: "INSTANCE",
|
|
26
|
+
size: { width: 720, height: 487 },
|
|
27
|
+
css: { display: "flex", flexDirection: "column", gap: "32px", ... },
|
|
28
|
+
text: "텍스트 내용" (TEXT 노드만),
|
|
29
|
+
imageRef: "abc123" (이미지 fill이 있는 노드만),
|
|
30
|
+
children: [...]
|
|
31
|
+
}
|
|
41
32
|
```
|
|
42
|
-
for each (변수명, url) in assets:
|
|
43
|
-
Bash: curl -sL "{url}" -o public/images/{feature}/{파일명}.webp
|
|
44
33
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
34
|
+
### Figma 속성 → CSS 변환표
|
|
35
|
+
|
|
36
|
+
도구가 자동으로 변환하는 속성:
|
|
37
|
+
|
|
38
|
+
| Figma 속성 | CSS | 스케일 적용 |
|
|
39
|
+
|-----------|-----|-----------|
|
|
40
|
+
| `fills[].color` | `background-color` | ❌ |
|
|
41
|
+
| `fills[].type=IMAGE` | `imageRef` (다운로드 대상) | — |
|
|
42
|
+
| `strokes[].color` + `strokeWeight` | `border` | ✅ (width만) |
|
|
43
|
+
| `effects[].DROP_SHADOW` | `box-shadow` | ✅ (px만) |
|
|
44
|
+
| `effects[].LAYER_BLUR` | `filter: blur()` | ✅ |
|
|
45
|
+
| `effects[].BACKGROUND_BLUR` | `backdrop-filter: blur()` | ✅ |
|
|
46
|
+
| `cornerRadius` | `border-radius` | ✅ |
|
|
47
|
+
| `opacity` | `opacity` | ❌ |
|
|
48
|
+
| `blendMode` | `mix-blend-mode` | ❌ |
|
|
49
|
+
| `style.fontFamily` | `font-family` | ❌ |
|
|
50
|
+
| `style.fontSize` | `font-size` | ✅ |
|
|
51
|
+
| `style.fontWeight` | `font-weight` | ❌ |
|
|
52
|
+
| `style.lineHeightPx` | `line-height` | ❌ (px이지만 상대값으로 취급) |
|
|
53
|
+
| `style.letterSpacing` | `letter-spacing` | ✅ |
|
|
54
|
+
| `style.textAlignHorizontal` | `text-align` | ❌ |
|
|
55
|
+
| `fills[].color` (TEXT) | `color` | ❌ |
|
|
56
|
+
| `characters` | 텍스트 내용 | — |
|
|
57
|
+
| `absoluteBoundingBox.width/height` | `width/height` | ✅ |
|
|
58
|
+
| `layoutMode=VERTICAL` | `display:flex; flex-direction:column` | ❌ |
|
|
59
|
+
| `layoutMode=HORIZONTAL` | `display:flex; flex-direction:row` | ❌ |
|
|
60
|
+
| `primaryAxisAlignItems` | `justify-content` | ❌ |
|
|
61
|
+
| `counterAxisAlignItems` | `align-items` | ❌ |
|
|
62
|
+
| `itemSpacing` | `gap` | ✅ |
|
|
63
|
+
| `padding*` | `padding` | ✅ |
|
|
64
|
+
| `clipsContent` | `overflow: hidden` | ❌ |
|
|
65
|
+
| `layoutPositioning=ABSOLUTE` | `position: absolute` | ❌ |
|
|
50
66
|
|
|
51
|
-
|
|
67
|
+
---
|
|
52
68
|
|
|
53
|
-
|
|
54
|
-
스크린샷에 보이는 이미지가 참조 코드에 에셋 URL로 없을 때:
|
|
69
|
+
## 2. 이미지 다운로드
|
|
55
70
|
|
|
56
|
-
1. get_metadata(섹션 nodeId)로 하위 노드 목록 확보
|
|
57
|
-
2. 이미지로 의심되는 하위 nodeId에 get_design_context 재호출
|
|
58
|
-
→ 에셋 URL 발견 시 다운로드
|
|
59
|
-
3. 그래도 없으면 → get_screenshot(해당 nodeId)으로 이미지 직접 저장
|
|
60
71
|
```
|
|
72
|
+
트리에서 imageRef 수집 → Figma API로 다운로드:
|
|
61
73
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
다운로드 완료 후 매핑 생성:
|
|
74
|
+
Bash:
|
|
75
|
+
node "[FIGMA_SCRIPT]" images {fileKey} {nodeId} --out={outDir} --depth=10
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
img21: '/images/{feature}/img-21.webp',
|
|
69
|
-
imgTitle: '/images/{feature}/title.webp',
|
|
70
|
-
imgSnowParticle12: '/images/{feature}/snow-particle-12.webp',
|
|
71
|
-
...
|
|
72
|
-
}
|
|
77
|
+
반환: { total: N, images: { "imageRef": "/path/to/file.png", ... } }
|
|
73
78
|
|
|
74
|
-
|
|
79
|
+
파일명: imageRef 앞 16자 + .png
|
|
80
|
+
검증: total = refs.size (누락 0), 0byte 파일 없음
|
|
75
81
|
```
|
|
76
82
|
|
|
77
83
|
---
|
|
78
84
|
|
|
79
|
-
##
|
|
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 변수 패턴
|
|
85
|
+
## 3. 스크린샷
|
|
125
86
|
|
|
126
87
|
```
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
text-[length:var(--font/size/heading/24,24px)]
|
|
130
|
-
text-[color:var(--color/grayscale/950,#171716)]
|
|
88
|
+
Bash:
|
|
89
|
+
node "[FIGMA_SCRIPT]" screenshot {fileKey} {nodeId} --out={path}
|
|
131
90
|
|
|
132
|
-
|
|
133
|
-
→ CSS 변수명은 프로젝트 토큰 네이밍에 참고.
|
|
91
|
+
시각 검증용. 노드를 PNG로 렌더링하여 저장.
|
|
134
92
|
```
|
|
135
93
|
|
|
136
94
|
---
|
|
137
95
|
|
|
138
|
-
##
|
|
96
|
+
## 4. 노드 구조 참조
|
|
139
97
|
|
|
140
98
|
```
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
112
|
```
|