@su-record/vibe 2.8.23 → 2.8.24
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/commands/vibe.figma.md +2 -2
- package/package.json +1 -1
- package/skills/vibe-figma/SKILL.md +173 -54
- package/skills/vibe-figma-convert/SKILL.md +176 -1
package/commands/vibe.figma.md
CHANGED
|
@@ -58,11 +58,11 @@ Load skill `vibe-figma` — Phase 0 Setup + Phase 1 Storyboard
|
|
|
58
58
|
|
|
59
59
|
## Phase 2: Design
|
|
60
60
|
|
|
61
|
-
Load skill `vibe-figma` — Phase 2 Design
|
|
61
|
+
Load skill `vibe-figma` — Phase 2 Design (비정형 레이어 감지 + 큰 섹션 분할 포함)
|
|
62
62
|
|
|
63
63
|
섹션별 처리 시 참조:
|
|
64
64
|
- Load skill `vibe-figma-extract` — 이미지 다운로드 + CSS 값 추출 방법
|
|
65
|
-
- Load skill `vibe-figma-convert` — 참조 코드 → 프로젝트 코드
|
|
65
|
+
- Load skill `vibe-figma-convert` — 참조 코드 → 프로젝트 코드 변환 (직역 모드 / 일반 모드)
|
|
66
66
|
|
|
67
67
|
## Phase 3: Verification
|
|
68
68
|
|
package/package.json
CHANGED
|
@@ -12,10 +12,23 @@ tier: standard
|
|
|
12
12
|
```
|
|
13
13
|
❌ CSS로 이미지 재현 (삼각형/원/gradient로 나무/눈사람/배경 그리기)
|
|
14
14
|
❌ 이미지 다운로드 없이 코드 생성 진행
|
|
15
|
-
❌ 컴포넌트 파일 안에 <style> 블록 / 인라인 style=""
|
|
16
15
|
❌ placeholder / 빈 template / 빈 src="" 남기기
|
|
17
16
|
❌ CSS 값을 추정 (참조 코드에 정확한 값이 있음)
|
|
18
17
|
❌ 브라우저 기본 스타일(검은색 16px)로 보이는 텍스트
|
|
18
|
+
❌ 핵심 에셋만 다운로드 (참조 코드의 모든 에셋을 빠짐없이 다운로드)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 스타일 배치 규칙 (모드별)
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
일반 모드:
|
|
25
|
+
❌ 컴포넌트 파일 안에 <style> 블록 / 인라인 style=""
|
|
26
|
+
✅ 외부 SCSS 파일에만 스타일 작성
|
|
27
|
+
|
|
28
|
+
직역 모드:
|
|
29
|
+
✅ <style scoped> 블록 허용 (Tailwind→CSS 1:1 변환)
|
|
30
|
+
✅ 인라인 :style="" 허용 (maskImage 등 동적 값)
|
|
31
|
+
❌ 외부 SCSS 파일에 추상화된 스타일 작성 (원본 좌표 손실)
|
|
19
32
|
```
|
|
20
33
|
|
|
21
34
|
## 전체 플로우
|
|
@@ -48,19 +61,19 @@ tier: standard
|
|
|
48
61
|
|
|
49
62
|
4. 디렉토리 생성:
|
|
50
63
|
- components/{feature}/
|
|
51
|
-
- styles/{feature}/ (layout/, components/ 하위)
|
|
52
64
|
- public/images/{feature}/ (또는 static/images/{feature}/)
|
|
65
|
+
- styles/{feature}/ (layout/, components/ 하위) — Phase 2에서 일반 모드 섹션이 있을 때만
|
|
53
66
|
```
|
|
54
67
|
|
|
55
68
|
---
|
|
56
69
|
|
|
57
70
|
## Phase 1: Storyboard
|
|
58
71
|
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
사용자에게 질문한다:
|
|
73
|
+
- question: "스토리보드 Figma URL을 입력해주세요. (없으면 '없음')"
|
|
74
|
+
- options 제공 금지 — 자유 텍스트 입력만 허용
|
|
61
75
|
|
|
62
|
-
"없음" → Phase 2로 건너뜀
|
|
63
|
-
```
|
|
76
|
+
"없음" 응답 시 → Phase 2로 건너뜀
|
|
64
77
|
|
|
65
78
|
### 1-1. 스토리보드 분석
|
|
66
79
|
|
|
@@ -68,11 +81,25 @@ AskUserQuestion: "스토리보드 Figma URL을 입력해주세요. (없으면 '
|
|
|
68
81
|
URL에서 fileKey, nodeId 추출
|
|
69
82
|
get_metadata(fileKey, nodeId) → 프레임 목록
|
|
70
83
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
⚠️ 메타데이터가 클 수 있음 (실전: 291K chars → 파일 저장됨)
|
|
85
|
+
→ 파일 저장 시 Python/Bash로 파싱하여 프레임 목록 추출
|
|
86
|
+
|
|
87
|
+
프레임 분류 (이름 패턴 기반, get_design_context 호출 전에 분류):
|
|
88
|
+
SPEC — "기능 정의서", "정책" → get_design_context로 텍스트 추출
|
|
89
|
+
CONFIG — "해상도", "브라우저" → get_design_context로 스케일 팩터 계산
|
|
90
|
+
SHARED — "공통", "GNB", "Footer", "Popup" → 공통 컴포넌트 파악
|
|
91
|
+
PAGE — "화면설계", "메인 -" → 섹션 목록 + 인터랙션 스펙
|
|
92
|
+
|
|
93
|
+
핵심 프레임 선별 (전부 읽지 않음):
|
|
94
|
+
1순위: SPEC (기능 정의서) — 1개
|
|
95
|
+
2순위: CONFIG (해상도) — 1개
|
|
96
|
+
3순위: PAGE 중 메인 섹션만 (3.1, 3.2, 3.3, 3.4, 3.5, 3.6)
|
|
97
|
+
하위 케이스(3.1.1, 3.2.1 등)는 건너뜀 — Phase 2에서 필요 시 참조
|
|
98
|
+
4순위: SHARED (공통 요소, Popup) — 필요 시
|
|
99
|
+
|
|
100
|
+
높이 1500px 이상 프레임:
|
|
101
|
+
→ get_design_context 대신 get_screenshot으로 시각 파악
|
|
102
|
+
→ 또는 get_metadata로 하위 분할 후 호출
|
|
76
103
|
```
|
|
77
104
|
|
|
78
105
|
### 1-2. 레이아웃 + 컴포넌트 구성 (코드 생성)
|
|
@@ -167,22 +194,23 @@ Phase 1 완료 조건:
|
|
|
167
194
|
Phase 1에서 컴포넌트가 이미 존재 (레이아웃 + 기능 주석 + 목 데이터).
|
|
168
195
|
Phase 2에서는 이 컴포넌트에 **디자인(이미지 + 스타일)**을 입힌다.
|
|
169
196
|
|
|
170
|
-
```
|
|
171
197
|
모바일 퍼스트 강제. CSS base = 최소 뷰포트, @media (min-width:)로 확장.
|
|
172
198
|
|
|
173
|
-
|
|
174
|
-
|
|
199
|
+
사용자에게 질문한다:
|
|
200
|
+
- question: "베이스 디자인(모바일) Figma URL을 입력해주세요."
|
|
201
|
+
- options 제공 금지 — 자유 텍스트 입력만 허용
|
|
202
|
+
|
|
203
|
+
→ base 스타일로 처리 (2-1, 2-2 실행).
|
|
175
204
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
205
|
+
처리 완료 후 다시 질문한다:
|
|
206
|
+
- question: "다음 브레이크포인트 디자인 URL을 입력해주세요. (없으면 '없음')"
|
|
207
|
+
- options 제공 금지
|
|
208
|
+
|
|
209
|
+
→ URL 입력 시: @media (min-width:) 레이어 추가 후 다시 질문
|
|
210
|
+
→ "없음" 응답 시: Phase 3으로
|
|
182
211
|
|
|
183
212
|
브레이크포인트는 프레임 width에서 자동 산출.
|
|
184
213
|
예: 720px → 480px(스케일), 2560px → 1920px(스케일) → @media (min-width: 1024px)
|
|
185
|
-
```
|
|
186
214
|
|
|
187
215
|
### 2-1. 스타일 파일 내용 작성 (첫 섹션 전)
|
|
188
216
|
|
|
@@ -196,7 +224,67 @@ Phase 1에서 빈 파일로 만든 스타일 구조에 기본 내용 Write:
|
|
|
196
224
|
styles/{feature}/components/ ← 디렉토리
|
|
197
225
|
```
|
|
198
226
|
|
|
199
|
-
### 2-2. 섹션별
|
|
227
|
+
### 2-2. 비정형 레이어 감지 (섹션별)
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
각 섹션의 get_design_context 응답을 받을 때마다 개별 판정.
|
|
231
|
+
한 페이지 내에서 섹션마다 모드가 다를 수 있음.
|
|
232
|
+
|
|
233
|
+
비정형 지표 (하나라도 해당 → 해당 섹션 직역 모드):
|
|
234
|
+
□ 에셋 URL 15개 이상
|
|
235
|
+
□ 소수점 좌표 사용 (left-[117.13px], top-[373.65px])
|
|
236
|
+
□ mix-blend-mode 사용 (mix-blend-lighten, mix-blend-multiply, mix-blend-hue)
|
|
237
|
+
□ rotate/scale 변환 사용 (rotate-[149.7deg], -scale-y-100)
|
|
238
|
+
□ mask-image 사용
|
|
239
|
+
□ blur 필터 사용 (blur-[3.5px])
|
|
240
|
+
□ 2560px 이상 원본 해상도에서 트리밍된 BG 구조
|
|
241
|
+
|
|
242
|
+
정형 지표 (전부 해당 → 해당 섹션 일반 모드):
|
|
243
|
+
□ flex/grid 기반 정형 레이아웃
|
|
244
|
+
□ 에셋 URL 10개 미만
|
|
245
|
+
□ absolute 좌표 없거나 정수값만
|
|
246
|
+
□ mix-blend/rotate/mask/blur 미사용
|
|
247
|
+
|
|
248
|
+
섹션별 판정 결과 테이블 출력:
|
|
249
|
+
┌──────────┬──────────┐
|
|
250
|
+
│ 섹션 │ 모드 │
|
|
251
|
+
├──────────┼──────────┤
|
|
252
|
+
│ Hero │ 직역 │
|
|
253
|
+
│ KID │ 직역 │
|
|
254
|
+
│ Daily │ 직역 │
|
|
255
|
+
│ Caution │ 일반 │
|
|
256
|
+
│ ... │ ... │
|
|
257
|
+
└──────────┴──────────┘
|
|
258
|
+
|
|
259
|
+
혼합 섹션 (배경=비정형, 콘텐츠=정형):
|
|
260
|
+
→ 직역 모드 적용 (비정형이 하나라도 있으면 직역)
|
|
261
|
+
→ 콘텐츠 영역의 반복 패턴(v-for 등)은 직역 내에서 유지
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 2-3. 큰 섹션 분할
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
get_design_context 타임아웃 방지:
|
|
268
|
+
|
|
269
|
+
섹션 높이가 1500px 이상이면 (모바일/PC 무관):
|
|
270
|
+
사전 분할: get_design_context 호출 전에 먼저 분할
|
|
271
|
+
1. get_metadata(섹션 nodeId)로 하위 노드 목록 확보
|
|
272
|
+
2. 하위 노드별로 get_design_context 호출 (분할)
|
|
273
|
+
3. 결과를 합쳐서 하나의 섹션으로 처리
|
|
274
|
+
|
|
275
|
+
타임아웃 발생 시 (분할 없이 호출한 경우):
|
|
276
|
+
1회 재시도 (excludeScreenshot: true)
|
|
277
|
+
→ 실패 시 즉시 분할 전략으로 전환 (3회 반복 금지)
|
|
278
|
+
→ 분할도 불가하면 get_screenshot + 스크린샷 기반 구현
|
|
279
|
+
(이 경우 CSS 값은 스크린샷에서 추정 — 품질 하락 감수)
|
|
280
|
+
|
|
281
|
+
실전 데이터 (PUBG 겨울 PC방 기준):
|
|
282
|
+
정상 응답: ~900px 이하 (KID 238px, Caution 880px, Anchor 652px)
|
|
283
|
+
타임아웃: 2000px+ (Daily 2372~3604, PlayTime 2000~2613, Exchange 2832~4342)
|
|
284
|
+
파일 저장: Hero 1280px (92K~130K chars — 에셋 40개로 크기 큼)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### 2-4. 섹션별 루프
|
|
200
288
|
|
|
201
289
|
**각 섹션에 대해 순서대로, 한 섹션을 완전히 완료한 후 다음으로:**
|
|
202
290
|
|
|
@@ -219,61 +307,92 @@ get_design_context(fileKey, 섹션.nodeId)
|
|
|
219
307
|
```
|
|
220
308
|
vibe-figma-extract 스킬 참조.
|
|
221
309
|
|
|
222
|
-
참조 코드에서 모든 에셋 URL 추출 → 다운로드 → 검증.
|
|
310
|
+
참조 코드에서 모든 에셋 URL을 빠짐없이 추출 → 다운로드 → 검증.
|
|
311
|
+
"핵심 에셋만" 금지. const img... 로 시작하는 모든 URL을 다운로드.
|
|
223
312
|
이미지가 모두 로컬에 있어야 c 단계로 진행.
|
|
224
313
|
하나라도 실패하면 코드 생성하지 않음.
|
|
225
314
|
```
|
|
226
315
|
|
|
227
|
-
#### c.
|
|
316
|
+
#### c. 코드 변환 (모드별 분기)
|
|
228
317
|
|
|
229
318
|
```
|
|
230
|
-
|
|
319
|
+
■ 직역 모드 (비정형 레이어):
|
|
320
|
+
vibe-figma-convert 스킬의 "직역 모드" 참조.
|
|
321
|
+
|
|
322
|
+
참조 코드의 JSX 구조 + Tailwind 클래스를 1:1로 변환:
|
|
323
|
+
- React JSX → Vue/Nuxt template (className→class 등)
|
|
324
|
+
- Tailwind 클래스 → <style scoped> 내 CSS 클래스 (값 그대로 유지)
|
|
325
|
+
- src={변수} → 로컬 이미지 경로
|
|
326
|
+
- style={{ maskImage: ... }} → :style="{ maskImage: ... }"
|
|
327
|
+
- 소수점 좌표, rotate, mix-blend-mode 전부 보존
|
|
328
|
+
- scaleFactor 적용: px 값만 스케일링, 나머지(색상, opacity, blend) 유지
|
|
329
|
+
|
|
330
|
+
외부 SCSS 파일 생성하지 않음.
|
|
331
|
+
컴포넌트에 <style scoped> 블록으로 스타일 포함.
|
|
231
332
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
text-[#1B3A1D] → color: #1B3A1D
|
|
235
|
-
bg-[#0A1628] → background-color: #0A1628
|
|
236
|
-
pt-[120px] → padding-top: 90px (120 × 0.75)
|
|
333
|
+
■ 일반 모드 (정형 레이어):
|
|
334
|
+
vibe-figma-convert 스킬의 기존 방식 참조.
|
|
237
335
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
336
|
+
참조 코드의 Tailwind 클래스에서 CSS 값 추출:
|
|
337
|
+
text-[48px] → font-size: 36px (48 × 0.75)
|
|
338
|
+
text-[#1B3A1D] → color: #1B3A1D
|
|
339
|
+
bg-[#0A1628] → background-color: #0A1628
|
|
340
|
+
pt-[120px] → padding-top: 90px (120 × 0.75)
|
|
341
|
+
|
|
342
|
+
Write/Edit:
|
|
343
|
+
styles/{feature}/layout/_{section}.scss ← 배치/구조/배경이미지
|
|
344
|
+
styles/{feature}/components/_{section}.scss ← 텍스트/버튼/카드 스타일
|
|
345
|
+
styles/{feature}/_tokens.scss ← 새 토큰 추가
|
|
242
346
|
```
|
|
243
347
|
|
|
244
348
|
#### d. Phase 1 컴포넌트 template 리팩토링
|
|
245
349
|
|
|
246
350
|
```
|
|
247
|
-
|
|
351
|
+
■ 직역 모드:
|
|
352
|
+
Phase 1 컴포넌트의 template을 참조 코드의 HTML 구조로 교체.
|
|
353
|
+
script(JSDoc, 인터페이스, 목 데이터, 핸들러)는 보존.
|
|
354
|
+
|
|
355
|
+
변환 핵심:
|
|
356
|
+
- 참조 코드의 div/img 구조를 거의 그대로 유지
|
|
357
|
+
- 모든 이미지 경로를 로컬 경로로 교체
|
|
358
|
+
- Phase 1의 기능 요소(v-for, @click, v-if)를 적절한 위치에 재배치
|
|
359
|
+
- <style scoped>에 Tailwind→CSS 변환 결과 포함
|
|
360
|
+
- 장식 이미지에 alt="" aria-hidden="true"
|
|
248
361
|
|
|
249
|
-
|
|
250
|
-
|
|
362
|
+
■ 일반 모드:
|
|
363
|
+
vibe-figma-convert 스킬 참조.
|
|
251
364
|
|
|
252
|
-
template
|
|
253
|
-
|
|
254
|
-
- 이미지 경로를 다운로드된 로컬 경로로 설정
|
|
255
|
-
- 배경 이미지 섹션은 Multi-Layer 구조 (.{section}Bg + .{section}Content)
|
|
256
|
-
- 클래스명을 외부 스타일 파일의 셀렉터와 매칭
|
|
257
|
-
- Phase 1의 기능 요소(v-for, @click, v-if)를 새 구조에 재배치
|
|
365
|
+
Phase 1에서 만든 컴포넌트의 template을 참조 코드 기반으로 리팩토링.
|
|
366
|
+
script(JSDoc 주석, 인터페이스, 목 데이터, 핸들러)는 보존.
|
|
258
367
|
|
|
259
|
-
|
|
368
|
+
template 변경 사항:
|
|
369
|
+
- 참조 코드의 HTML 구조를 프로젝트 스택으로 변환
|
|
370
|
+
- 이미지 경로를 다운로드된 로컬 경로로 설정
|
|
371
|
+
- 배경 이미지 섹션은 Multi-Layer 구조 (.{section}Bg + .{section}Content)
|
|
372
|
+
- 클래스명을 외부 스타일 파일의 셀렉터와 매칭
|
|
373
|
+
- Phase 1의 기능 요소(v-for, @click, v-if)를 새 구조에 재배치
|
|
374
|
+
|
|
375
|
+
컴포넌트에 <style> 블록 없음. 스타일은 전부 외부 파일.
|
|
260
376
|
```
|
|
261
377
|
|
|
262
378
|
#### e. 섹션 검증
|
|
263
379
|
|
|
264
380
|
```
|
|
265
|
-
|
|
266
|
-
□ "figma.com/api" in 생성 파일 → 0건
|
|
267
|
-
□ "
|
|
268
|
-
□ "
|
|
269
|
-
□
|
|
381
|
+
공통 체크:
|
|
382
|
+
□ Grep: "figma.com/api" in 생성 파일 → 0건
|
|
383
|
+
□ Grep: "placeholder" in 컴포넌트 파일 → 0건
|
|
384
|
+
□ Grep: 'src=""' in 컴포넌트 파일 → 0건
|
|
385
|
+
□ Glob: images/{feature}/*.webp → 이미지 파일 존재
|
|
386
|
+
□ Read: 컴포넌트 template에 실제 HTML 태그 존재 (빈 template 아님)
|
|
270
387
|
|
|
271
|
-
|
|
272
|
-
□
|
|
273
|
-
□
|
|
388
|
+
일반 모드 추가 체크:
|
|
389
|
+
□ Grep: "<style" in 컴포넌트 파일 → 0건
|
|
390
|
+
□ Grep: 'style="' in 컴포넌트 파일 → 0건
|
|
391
|
+
□ Read: 외부 스타일 파일에 font-size, color, background-image 존재
|
|
274
392
|
|
|
275
|
-
|
|
276
|
-
□
|
|
393
|
+
직역 모드 추가 체크:
|
|
394
|
+
□ Read: <style scoped> 블록에 position, transform, mix-blend-mode 존재
|
|
395
|
+
□ 에셋 수 = 다운로드된 이미지 수 (누락 0)
|
|
277
396
|
|
|
278
397
|
실패 시 → 해당 항목 수정 → 재검증
|
|
279
398
|
```
|
|
@@ -7,7 +7,182 @@ tier: standard
|
|
|
7
7
|
|
|
8
8
|
# vibe-figma-convert — 코드 변환
|
|
9
9
|
|
|
10
|
-
`get_design_context` 참조 코드를 프로젝트 스택
|
|
10
|
+
`get_design_context` 참조 코드를 프로젝트 스택 코드로 변환.
|
|
11
|
+
**두 가지 모드**: 일반 모드(외부 SCSS) / 직역 모드(scoped CSS).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 0. 직역 모드 (비정형 레이어)
|
|
16
|
+
|
|
17
|
+
비정형 레이어 감지 시 사용. 참조 코드의 구조와 좌표를 **거의 그대로** 보존.
|
|
18
|
+
|
|
19
|
+
### 핵심 원칙
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
1. 참조 코드의 HTML 중첩 구조를 1:1로 유지
|
|
23
|
+
2. absolute 좌표, rotate, mix-blend-mode, blur 등 시각 속성 전부 보존
|
|
24
|
+
3. scaleFactor는 px 값에만 적용 (색상, opacity, blend-mode, z-index 미적용)
|
|
25
|
+
4. 에셋 URL → 로컬 경로로만 교체
|
|
26
|
+
5. 의미론적 재구성(BG+Content 분리) 시도하지 않음
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Tailwind → CSS 클래스 직역
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
참조 코드의 각 요소에 고유 클래스명을 부여하고,
|
|
33
|
+
Tailwind 클래스를 CSS로 1:1 변환하여 <style scoped>에 작성.
|
|
34
|
+
|
|
35
|
+
클래스명 규칙: data-name 또는 data-node-id 기반
|
|
36
|
+
data-name="BG" → .bg
|
|
37
|
+
data-name="Period" → .period
|
|
38
|
+
data-name="Title" → .title
|
|
39
|
+
data-name="Light" → .light
|
|
40
|
+
이름 없으면 → .node-{nodeId} (콜론→하이픈)
|
|
41
|
+
|
|
42
|
+
변환 예시:
|
|
43
|
+
className="absolute h-[1280px] left-0 overflow-clip top-0 w-[720px]"
|
|
44
|
+
→
|
|
45
|
+
.bg {
|
|
46
|
+
position: absolute;
|
|
47
|
+
height: 853px; /* 1280 × 0.667 */
|
|
48
|
+
left: 0;
|
|
49
|
+
overflow: clip;
|
|
50
|
+
top: 0;
|
|
51
|
+
width: 100%; /* 720px = 뷰포트 전체폭 → 100% */
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
className="-translate-x-1/2 absolute h-[174px] left-1/2 top-1/2 w-[620px]"
|
|
55
|
+
→
|
|
56
|
+
.title-img {
|
|
57
|
+
position: absolute;
|
|
58
|
+
height: 116px; /* 174 × 0.667 */
|
|
59
|
+
left: 50%;
|
|
60
|
+
top: 50%;
|
|
61
|
+
transform: translateX(-50%);
|
|
62
|
+
width: 413px; /* 620 × 0.667 */
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 특수 패턴 직역
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
mix-blend:
|
|
70
|
+
className="mix-blend-lighten"
|
|
71
|
+
→ mix-blend-mode: lighten;
|
|
72
|
+
|
|
73
|
+
rotate + scale:
|
|
74
|
+
className="-scale-y-100 rotate-[149.7deg]"
|
|
75
|
+
→ transform: scaleY(-1) rotate(149.7deg);
|
|
76
|
+
|
|
77
|
+
mask-image:
|
|
78
|
+
style={{ maskImage: `url('${imgVar}')` }}
|
|
79
|
+
→ :style="{ maskImage: `url('/images/{feature}/파일.webp')` }"
|
|
80
|
+
(Vue 동적 바인딩으로 변환)
|
|
81
|
+
|
|
82
|
+
blur:
|
|
83
|
+
className="blur-[3.5px]"
|
|
84
|
+
→ filter: blur(3.5px);
|
|
85
|
+
|
|
86
|
+
소수점 좌표:
|
|
87
|
+
className="absolute h-[141.67px] left-[380.52px] top-[528.95px]"
|
|
88
|
+
→ position: absolute;
|
|
89
|
+
height: 94px; /* 141.67 × 0.667 반올림 */
|
|
90
|
+
left: 254px; /* 380.52 × 0.667 반올림 */
|
|
91
|
+
top: 353px; /* 528.95 × 0.667 반올림 */
|
|
92
|
+
|
|
93
|
+
inset-[-18.13%]:
|
|
94
|
+
→ inset: -18.13%; (% 값은 스케일링 안 함)
|
|
95
|
+
|
|
96
|
+
overflow-hidden + 스프라이트:
|
|
97
|
+
className="absolute h-full left-[-129.09%] max-w-none top-0 w-[229.09%]"
|
|
98
|
+
→ position: absolute;
|
|
99
|
+
height: 100%;
|
|
100
|
+
left: -129.09%; /* % 값 그대로 */
|
|
101
|
+
max-width: none;
|
|
102
|
+
top: 0;
|
|
103
|
+
width: 229.09%; /* % 값 그대로 */
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Vue SFC 출력 형태
|
|
107
|
+
|
|
108
|
+
```vue
|
|
109
|
+
<template>
|
|
110
|
+
<section class="heroSection">
|
|
111
|
+
<!-- 참조 코드의 HTML 구조를 1:1 유지 -->
|
|
112
|
+
<div class="bg">
|
|
113
|
+
<div class="bgInner">
|
|
114
|
+
<div class="bgImage1">
|
|
115
|
+
<img src="/images/{feature}/bg.webp" alt="" aria-hidden="true" />
|
|
116
|
+
</div>
|
|
117
|
+
<div class="tree4">
|
|
118
|
+
<img src="/images/{feature}/tree-4.webp" alt="" aria-hidden="true" />
|
|
119
|
+
</div>
|
|
120
|
+
<!-- ... 모든 서브 레이어 유지 -->
|
|
121
|
+
</div>
|
|
122
|
+
<!-- ... -->
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<!-- 콘텐츠 영역 (참조 코드의 Title, Period 등) -->
|
|
126
|
+
<div class="titleArea">
|
|
127
|
+
<div class="titleImg">
|
|
128
|
+
<img src="/images/{feature}/title.webp" alt="추운 겨울, 따뜻한 보상이 펑펑" />
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</section>
|
|
132
|
+
</template>
|
|
133
|
+
|
|
134
|
+
<script setup lang="ts">
|
|
135
|
+
// Phase 1의 script 보존
|
|
136
|
+
</script>
|
|
137
|
+
|
|
138
|
+
<style scoped>
|
|
139
|
+
.heroSection {
|
|
140
|
+
position: relative;
|
|
141
|
+
width: 100%;
|
|
142
|
+
height: 853px; /* 1280 × 0.667 */
|
|
143
|
+
overflow: hidden;
|
|
144
|
+
}
|
|
145
|
+
.bg {
|
|
146
|
+
position: absolute;
|
|
147
|
+
height: 853px;
|
|
148
|
+
left: 0;
|
|
149
|
+
overflow: clip;
|
|
150
|
+
top: 0;
|
|
151
|
+
width: 100%;
|
|
152
|
+
}
|
|
153
|
+
.tree4 {
|
|
154
|
+
position: absolute;
|
|
155
|
+
bottom: 215px;
|
|
156
|
+
height: 453px;
|
|
157
|
+
left: 50%;
|
|
158
|
+
transform: translateX(calc(-50% + 599px));
|
|
159
|
+
opacity: 0.4;
|
|
160
|
+
width: 1727px;
|
|
161
|
+
}
|
|
162
|
+
.tree4 img {
|
|
163
|
+
position: absolute;
|
|
164
|
+
inset: 0;
|
|
165
|
+
max-width: none;
|
|
166
|
+
object-fit: cover;
|
|
167
|
+
pointer-events: none;
|
|
168
|
+
width: 100%;
|
|
169
|
+
height: 100%;
|
|
170
|
+
}
|
|
171
|
+
/* ... 모든 레이어의 CSS */
|
|
172
|
+
</style>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 직역 모드에서의 반응형
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
첫 번째 URL → <style scoped>에 base 스타일
|
|
179
|
+
두 번째 URL → 같은 <style scoped> 안에 @media (min-width:) 추가
|
|
180
|
+
기존 스타일 삭제 금지
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 이하: 일반 모드 (정형 레이어)
|
|
11
186
|
|
|
12
187
|
---
|
|
13
188
|
|