@su-record/vibe 2.8.48 → 2.8.49
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/hooks/scripts/figma-extract.js +141 -16
- package/package.json +1 -1
- package/skills/vibe.figma/SKILL.md +106 -961
- package/skills/vibe.figma.convert/SKILL.md +91 -14
- package/skills/vibe.figma.extract/SKILL.md +44 -7
|
@@ -141,14 +141,29 @@ tree.json의 css 객체를 SCSS로 직접 변환한다. 추정하지 않는다.
|
|
|
141
141
|
node.css.justifyContent → justify-content
|
|
142
142
|
node.css.alignItems → align-items
|
|
143
143
|
node.css.gap → gap (→ vw 변환)
|
|
144
|
+
node.css.flexGrow → flex-grow (값 그대로)
|
|
144
145
|
node.css.padding → padding (→ vw 변환)
|
|
145
146
|
node.css.width → width (→ vw 또는 % 변환)
|
|
146
147
|
node.css.height → height (→ vw 변환, 또는 auto)
|
|
147
148
|
node.css.overflow → overflow
|
|
148
149
|
node.css.position → position
|
|
150
|
+
node.css.top → top (→ vw 변환, absolute 노드만)
|
|
151
|
+
node.css.left → left (→ vw 변환, absolute 노드만)
|
|
152
|
+
node.css.transform → transform (rotate — 값 그대로)
|
|
153
|
+
|
|
154
|
+
layoutSizing 처리 (node.layoutSizingH / node.layoutSizingV):
|
|
155
|
+
HUG → css에 width/height 없음 (auto). SCSS에서 생략하면 auto 동작.
|
|
156
|
+
FILL → 부모 flex-direction 확인 후 결정:
|
|
157
|
+
부모 row + 자식 FILL-H → flex: 1 0 0 (또는 width: 100%)
|
|
158
|
+
부모 column + 자식 FILL-V → flex: 1 0 0 (또는 height: 100%)
|
|
159
|
+
부모 row + 자식 FILL-V → align-self: stretch
|
|
160
|
+
부모 column + 자식 FILL-H → align-self: stretch
|
|
161
|
+
FIXED → css.width/height의 px 값을 vw로 변환 (기존 방식)
|
|
149
162
|
|
|
150
163
|
비주얼 (components/ 파일):
|
|
151
164
|
node.css.backgroundColor → background-color
|
|
165
|
+
node.css.backgroundImage → background-image (gradient — 값 그대로)
|
|
166
|
+
node.css.backgroundBlendMode → background-blend-mode (값 그대로)
|
|
152
167
|
node.css.color → color
|
|
153
168
|
node.css.fontFamily → font-family
|
|
154
169
|
node.css.fontSize → font-size (→ clamp 변환)
|
|
@@ -157,20 +172,35 @@ tree.json의 css 객체를 SCSS로 직접 변환한다. 추정하지 않는다.
|
|
|
157
172
|
node.css.letterSpacing → letter-spacing (→ vw 변환)
|
|
158
173
|
node.css.textAlign → text-align
|
|
159
174
|
node.css.borderRadius → border-radius (→ vw 변환)
|
|
160
|
-
node.css.border → border (width → vw
|
|
175
|
+
node.css.border → border (width → vw 변환, strokeAlign=INSIDE)
|
|
176
|
+
node.css.outline → outline (width → vw 변환, strokeAlign=OUTSIDE)
|
|
177
|
+
node.css.boxSizing → box-sizing (INSIDE stroke → border-box)
|
|
161
178
|
node.css.boxShadow → box-shadow (px → vw 변환)
|
|
162
179
|
node.css.opacity → opacity
|
|
163
180
|
node.css.mixBlendMode → mix-blend-mode
|
|
164
|
-
node.css.filter → filter (px → vw
|
|
181
|
+
node.css.filter → filter (blur px → vw 변환, grayscale/saturate → 값 그대로)
|
|
165
182
|
node.css.backdropFilter → backdrop-filter (px → vw 변환)
|
|
166
183
|
|
|
184
|
+
이미지 처리 (node.imageScaleMode):
|
|
185
|
+
FILL → background-size: cover
|
|
186
|
+
FIT → background-size: contain
|
|
187
|
+
CROP → background-size: cover; background-position: center
|
|
188
|
+
TILE → background-size: auto; background-repeat: repeat
|
|
189
|
+
|
|
190
|
+
다중 fill (node.fills 배열, 2개 이상일 때):
|
|
191
|
+
예: [IMAGE(grayscale) + GRADIENT_LINEAR] → 겹침 배경
|
|
192
|
+
CSS: background: url('img.webp'), linear-gradient(...);
|
|
193
|
+
background-blend-mode: multiply;
|
|
194
|
+
filter: grayscale(100%);
|
|
195
|
+
converter는 fills 배열 순서대로 CSS background 레이어링
|
|
196
|
+
|
|
167
197
|
반응형 단위 변환 (scaleFactor 사용하지 않음):
|
|
168
198
|
스토리보드 CONFIG에서 확보:
|
|
169
199
|
designWidth: 디자인 너비 (예: 720px 모바일, 2560px PC)
|
|
170
200
|
minWidth: 최소 지원 너비 (예: 340px)
|
|
171
201
|
breakpoint: PC/모바일 분계 (예: 1025px)
|
|
172
202
|
|
|
173
|
-
UI 요소 (width, height, padding, gap, border-radius, shadow 등):
|
|
203
|
+
UI 요소 (width, height, padding, gap, border-radius, shadow, top, left 등):
|
|
174
204
|
→ vw 비례: vw값 = (Figma px / designWidth) × 100
|
|
175
205
|
→ 예: gap: 24px / 720 × 100 = 3.33vw
|
|
176
206
|
→ width: 부모 대비 %도 가능 (620/720 = 86%)
|
|
@@ -196,7 +226,9 @@ tree.json의 css 객체를 SCSS로 직접 변환한다. 추정하지 않는다.
|
|
|
196
226
|
|
|
197
227
|
변환하지 않는 속성:
|
|
198
228
|
color, opacity, font-weight, font-family, z-index,
|
|
199
|
-
line-height(단위 없을 때), text-align, mix-blend-mode
|
|
229
|
+
line-height(단위 없을 때), text-align, mix-blend-mode,
|
|
230
|
+
transform(rotate), background-blend-mode, flex-grow,
|
|
231
|
+
box-sizing, grayscale/saturate(filter 내)
|
|
200
232
|
|
|
201
233
|
값이 없으면:
|
|
202
234
|
→ 해당 속성 생략 (추정 금지)
|
|
@@ -476,7 +508,15 @@ function handleShare(): void {
|
|
|
476
508
|
조건: BG 프레임 (name에 BG/bg 또는 부모와 크기 동일)
|
|
477
509
|
❌ <img> 태그 금지
|
|
478
510
|
✅ CSS background-image로만 처리:
|
|
479
|
-
부모 { background-image: url('...');
|
|
511
|
+
부모 { background-image: url('...'); }
|
|
512
|
+
imageScaleMode에 따라:
|
|
513
|
+
FILL → background-size: cover (기본)
|
|
514
|
+
FIT → background-size: contain
|
|
515
|
+
CROP → background-size: cover; background-position: center
|
|
516
|
+
TILE → background-size: auto; background-repeat: repeat
|
|
517
|
+
다중 fill (node.fills 배열):
|
|
518
|
+
background: url('img.webp'), linear-gradient(...);
|
|
519
|
+
background-blend-mode: multiply;
|
|
480
520
|
|
|
481
521
|
콘텐츠 이미지:
|
|
482
522
|
조건: imageRef 있음 + 독립적 크기 + TEXT 형제 없음
|
|
@@ -496,21 +536,58 @@ function handleShare(): void {
|
|
|
496
536
|
|
|
497
537
|
---
|
|
498
538
|
|
|
499
|
-
## 5. 반응형 추가 (
|
|
539
|
+
## 5. 반응형 추가 (MO↔PC 매칭)
|
|
500
540
|
|
|
501
541
|
```
|
|
502
|
-
|
|
542
|
+
remapped.json의 pcDiff를 사용하여 @media 오버라이드 추가.
|
|
543
|
+
MO 기본 코드 삭제 금지. PC는 항상 @media 블록 안에만 작성.
|
|
544
|
+
|
|
545
|
+
SCSS 구조:
|
|
546
|
+
.heroSection {
|
|
547
|
+
// MO 기본 (vw = px / 720 × 100)
|
|
548
|
+
width: 100%;
|
|
549
|
+
height: 177.78vw;
|
|
550
|
+
background-image: url('/images/{feature}/hero-bg.webp');
|
|
551
|
+
|
|
552
|
+
@media (min-width: #{$bp-desktop}) {
|
|
553
|
+
// PC 오버라이드 (vw = px / 2560 × 100, 또는 고정 px)
|
|
554
|
+
height: 32.66vw; // 836 / 2560 × 100
|
|
555
|
+
background-image: url('/images/{feature}/hero-bg-pc.webp');
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
CSS diff 처리 규칙:
|
|
560
|
+
|
|
561
|
+
같은 값 → MO만 유지 (PC에 쓰지 않음)
|
|
562
|
+
|
|
563
|
+
다른 px 값:
|
|
564
|
+
→ @media { 속성: PC값/pcDesignWidth × 100 vw; }
|
|
565
|
+
→ 예: MO gap:24px → 3.33vw, PC gap:60px → @media { gap: 2.34vw; }
|
|
566
|
+
|
|
567
|
+
다른 레이아웃:
|
|
568
|
+
→ @media { flex-direction: row; }
|
|
569
|
+
→ @media { justify-content: space-between; }
|
|
570
|
+
|
|
571
|
+
다른 이미지:
|
|
572
|
+
→ @media { background-image: url('/images/{feature}/pc-xxx.webp'); }
|
|
573
|
+
|
|
574
|
+
layoutSizing diff:
|
|
575
|
+
MO: HUG → PC: FIXED → @media { width: Xvw; }
|
|
576
|
+
MO: FILL → PC: FIXED → @media { width: Xvw; flex: initial; }
|
|
577
|
+
MO: FIXED → PC: FILL → @media { flex: 1 0 0; width: auto; }
|
|
578
|
+
|
|
579
|
+
MO에만 있는 속성 → MO 기본값 유지
|
|
580
|
+
PC에만 있는 속성 → @media에서 추가
|
|
581
|
+
PC에서 사라진 속성 → @media { display: none; } 또는 생략
|
|
503
582
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
CSS 속성 차이만 @media 오버라이드로 추가
|
|
583
|
+
absolute 위치 diff:
|
|
584
|
+
→ @media { top: PC값/pcDesignWidth × 100 vw; left: ...; }
|
|
507
585
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
다른 레이아웃 → @include pc { flex-direction: row; }
|
|
511
|
-
다른 이미지 → @include pc { content: url(/images/{feature}/desktop-xxx.webp); }
|
|
586
|
+
rotation diff:
|
|
587
|
+
→ @media { transform: rotate(PC각도deg); }
|
|
512
588
|
|
|
513
589
|
기존 모바일 코드 삭제 금지.
|
|
590
|
+
PC 오버라이드는 항상 @media 블록 안에만.
|
|
514
591
|
```
|
|
515
592
|
|
|
516
593
|
---
|
|
@@ -65,27 +65,53 @@ Bash:
|
|
|
65
65
|
|
|
66
66
|
트리 추출 도구가 자동 변환하는 속성. **이 값들이 SCSS에 직접 매핑된다:**
|
|
67
67
|
|
|
68
|
+
**레이아웃:**
|
|
69
|
+
|
|
68
70
|
| Figma 속성 | CSS | vw 변환 |
|
|
69
|
-
|
|
71
|
+
|-----------|-----|---------|
|
|
70
72
|
| `layoutMode=VERTICAL` | `display:flex; flex-direction:column` | ❌ |
|
|
71
73
|
| `layoutMode=HORIZONTAL` | `display:flex; flex-direction:row` | ❌ |
|
|
72
74
|
| `primaryAxisAlignItems` | `justify-content` | ❌ |
|
|
73
75
|
| `counterAxisAlignItems` | `align-items` | ❌ |
|
|
74
76
|
| `itemSpacing` | `gap` | ✅ |
|
|
77
|
+
| `layoutGrow=1` | `flex-grow: 1` | ❌ |
|
|
75
78
|
| `padding*` | `padding` | ✅ |
|
|
76
79
|
| `absoluteBoundingBox.width/height` | `width/height` | ✅ |
|
|
77
|
-
| `layoutPositioning=ABSOLUTE` | `position: absolute` |
|
|
80
|
+
| `layoutPositioning=ABSOLUTE` | `position: absolute` + `top/left` (부모 상대 좌표) | ✅ |
|
|
81
|
+
| `layoutSizingHorizontal=HUG` | width 삭제 (auto) | — |
|
|
82
|
+
| `layoutSizingHorizontal=FILL` | 메타데이터 `layoutSizingH` (converter가 flex:1/100% 결정) | — |
|
|
83
|
+
| `layoutSizingVertical=HUG` | height 삭제 (auto) | — |
|
|
84
|
+
| `layoutSizingVertical=FILL` | 메타데이터 `layoutSizingV` (converter가 결정) | — |
|
|
78
85
|
| `clipsContent` | `overflow: hidden` | ❌ |
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
|
|
87
|
+
**비주얼:**
|
|
88
|
+
|
|
89
|
+
| Figma 속성 | CSS | vw 변환 |
|
|
90
|
+
|-----------|-----|---------|
|
|
91
|
+
| `fills[].SOLID` | `background-color` | ❌ |
|
|
92
|
+
| `fills[].IMAGE` | `imageRef` + `imageScaleMode` (FILL/FIT/CROP/TILE) | — |
|
|
93
|
+
| `fills[].GRADIENT_LINEAR` | `background-image: linear-gradient(...)` | ❌ |
|
|
94
|
+
| `fills[].GRADIENT_RADIAL` | `background-image: radial-gradient(...)` | ❌ |
|
|
95
|
+
| `fills[] (2개 이상)` | `fills` 배열 (type, color, imageRef, gradient, blendMode, filters) | — |
|
|
96
|
+
| `fills[].blendMode` | `background-blend-mode` | ❌ |
|
|
97
|
+
| `fills[].filters.saturation` | `filter: grayscale(X%)` / `saturate(X%)` | ❌ |
|
|
81
98
|
| `fills[].color` (TEXT) | `color` | ❌ |
|
|
82
|
-
| `strokes[]
|
|
99
|
+
| `strokes[] + strokeAlign=INSIDE` | `border` + `box-sizing: border-box` | ✅ (width만) |
|
|
100
|
+
| `strokes[] + strokeAlign=OUTSIDE` | `outline` | ✅ (width만) |
|
|
101
|
+
| `strokes[] + strokeAlign=CENTER` | `border` | ✅ (width만) |
|
|
83
102
|
| `effects[].DROP_SHADOW` | `box-shadow` | ✅ (px만) |
|
|
84
|
-
| `effects[].
|
|
103
|
+
| `effects[].INNER_SHADOW` | `box-shadow` (inset) | ✅ (px만) |
|
|
104
|
+
| `effects[].LAYER_BLUR` | `filter: blur()` (누적) | ✅ |
|
|
85
105
|
| `effects[].BACKGROUND_BLUR` | `backdrop-filter: blur()` | ✅ |
|
|
86
106
|
| `cornerRadius` | `border-radius` | ✅ |
|
|
87
107
|
| `opacity` | `opacity` | ❌ |
|
|
88
|
-
| `
|
|
108
|
+
| `rotation` | `transform: rotate(Xdeg)` | ❌ |
|
|
109
|
+
| `blendMode` (노드 레벨) | `mix-blend-mode` | ❌ |
|
|
110
|
+
|
|
111
|
+
**텍스트:**
|
|
112
|
+
|
|
113
|
+
| Figma 속성 | CSS | vw 변환 |
|
|
114
|
+
|-----------|-----|---------|
|
|
89
115
|
| `style.fontFamily` | `font-family` | ❌ |
|
|
90
116
|
| `style.fontSize` | `font-size` | ✅ |
|
|
91
117
|
| `style.fontWeight` | `font-weight` | ❌ |
|
|
@@ -94,6 +120,17 @@ Bash:
|
|
|
94
120
|
| `style.textAlignHorizontal` | `text-align` | ❌ |
|
|
95
121
|
| `characters` | 텍스트 내용 | — |
|
|
96
122
|
|
|
123
|
+
### FigmaNode 메타데이터 필드 (css 외)
|
|
124
|
+
|
|
125
|
+
converter가 의사결정에 사용하는 추가 필드:
|
|
126
|
+
|
|
127
|
+
| 필드 | 타입 | 용도 |
|
|
128
|
+
|------|------|------|
|
|
129
|
+
| `layoutSizingH` | `'FIXED'\|'HUG'\|'FILL'` | 부모 context로 width 결정 |
|
|
130
|
+
| `layoutSizingV` | `'FIXED'\|'HUG'\|'FILL'` | 부모 context로 height 결정 |
|
|
131
|
+
| `imageScaleMode` | `'FILL'\|'FIT'\|'CROP'\|'TILE'` | background-size 결정 |
|
|
132
|
+
| `fills` | `array` | 다중 fill 레이어 상세 (2개 이상일 때만) |
|
|
133
|
+
|
|
97
134
|
---
|
|
98
135
|
|
|
99
136
|
## 2. 이미지 에셋 — 노드 렌더링 기반 (imageRef 개별 다운로드 금지)
|