diff --git a/FIGMA-DESIGN-LANGUAGE.md b/FIGMA-DESIGN-LANGUAGE.md new file mode 100644 index 0000000..b714ea9 --- /dev/null +++ b/FIGMA-DESIGN-LANGUAGE.md @@ -0,0 +1,112 @@ +# Figma Design Language Analysis + +> Phase 1 결과 문서 (2026-04-07) +> Figma Source: `9S6LsQyO6zlRxtiqZccOUM` / Page 1 + +## 1. 스코프 + +| 프레임 | 역할 | 판정 | +|--------|------|------| +| Frame 1 (1:3) | 3D 수렴 화살표 | 서브 컴포넌트 (장식 이미지) | +| Frame 2 (1:5) | Solution 제작 목표 | **블록화** → hero-icon-cards | +| Frame 3 (1:35) | 정책 달성 (Engn.Solution vs DfMA) | **블록화** → compare-2col-badge | +| Frame 4 (1:49) | 과정 vs 결과의 혁신 | **블록화** → compare-detail-gradient | +| Frame 5 (1:74) | 상세보기 버튼 | 서브 컴포넌트 (CTA) | +| Frame 6 (1:80) | 정책방향 (세로 문서) | **제외** (1280×720 부적합) | + +## 2. 스케일 변환 + +Figma 캔버스 → 슬라이드(1280px) 변환 비율: +- Frame 2, 3: ×0.71 (1808px → 1280px) +- Frame 4: ×0.33 (3848px, 양쪽 합쳐서 2패널) + +| Figma | 슬라이드 환산 | 역할 | +|-------|-------------|------| +| 70px | 28-35px | 대섹션 헤더 | +| 60px | 24-28px | Hero 메시지 | +| 50px | 22-26px | 섹션 제목, 배지 | +| 45px | 20-22px | 카드 타이틀 (EN) | +| 40px | 16-20px | 본문 | +| 35px | 14-18px | 부제, 한국어 서브 | +| 32px | 12-14px | 버튼 | + +## 3. 색상 팔레트 (Warm Theme) + +기존 블루/슬레이트 테마와 **병존**하는 새 팔레트: + +| 토큰 | Hex | Figma 원본 | 용도 | +|------|-----|-----------|------| +| `--color-warm-brown` | `#5C3714` | rgba(92,55,20) | 과정/프로세스 섹션 제목 | +| `--color-dark-teal` | `#084C56` | rgba(8,76,86) | 결과/디지털 섹션 제목 | +| `--color-teal` | `#227582` | rgba(34,117,130) | 설명 텍스트 | +| `--color-forest` | `#548235` | rgba(84,130,53) | 배경 그라디언트 | +| `--color-beige` | `#E4D9C0` | rgba(228,217,192) | 서브틀 배경/버튼 | +| `--color-warm-yellow` | `#FAEDCB` | rgba(250,237,203) | 하이라이트 바 | + +### 그라디언트 패턴 +- 왼쪽(과정): `rgba(165,161,150,0.10) → rgba(57,50,30,1.00)` (베이지→브라운) +- 오른쪽(결과): `rgba(41,107,85,0.10) → rgba(3,33,24,1.00)` (틸→다크) +- 버튼: `rgba(255,255,255,0.00) → rgba(228,217,192,1.00)` (투명→베이지) +- 배경: `rgba(84,130,53,1.00) → rgba(37,62,31,0.00)` (그린→투명) + +## 4. 타이포그래피 + +- **폰트**: Pretendard Variable 유지 (Noto Sans KR은 이미 fallback) +- **핵심은 크기/굵기 위계** + +| 레벨 | 크기 (슬라이드) | Weight | 스트로크 | 정렬 | +|------|---------------|--------|---------|------| +| Hero Statement | 24-28px | 700 | white 1.5px | center | +| Section Header | 28-35px | 900 | white 5px | center/left | +| Badge Title | 22-26px | 700 | 없음 | center | +| Card Title (EN) | 20-22px | 900 | white 5px | center | +| Card Subtitle (KR) | 14-18px | 500 | white 1.5px | center | +| Body Text | 16-20px | 700 | white 1px | left | +| Section Sub-title | 22-26px | 900 | 없음 | left | + +### 텍스트 스트로크 기법 +Figma 디자인의 특징: 다양한 배경 위에서 가독성 확보를 위해 **흰색 스트로크** 사용 +```css +-webkit-text-stroke: 1.5px white; /* 일반 텍스트 */ +-webkit-text-stroke: 5px white; /* 강조 텍스트 */ +paint-order: stroke fill; /* 스트로크가 텍스트 뒤로 */ +``` + +## 5. 레이아웃 패턴 + +### A. Badge Header +- 이미지/그라디언트 배경 위 `border-radius: 20px` 바 +- 중앙 흰색 텍스트 (50px/700 → 22-26px/700) +- 높이: ~88px (Figma) → ~44-50px (슬라이드) + +### B. Hero Statement +- 전체 폭 중앙 정렬 +- 큰 텍스트 (60px/700) + 흰색 스트로크 +- 키워드 **굵은 강조** 가능 + +### C. Icon Card Row +- N개 카드 수평 배치, 세로 구분선 +- 각 카드: 아이콘 이미지 + 영문 제목(900) + 한국어 부제(500) +- 흰색 둥근 컨테이너 (borderRadius: 20) + +### D. Two-Col Comparison +- 좌/우 그라디언트 배경 +- 각 열: 헤더 바 + (섹션 제목 + 본문) × N개 +- 색상으로 좌/우 구분 (브라운 vs 틸) + +### E. CTA Button +- 그라디언트 바 (투명→베이지) + 둥근 버튼 (r:7) +- 흰색 텍스트 + +## 6. 디자인 시스템 vs 콘텐츠 전용 경계 + +### 디자인 시스템 (블록에 포함) +- 색상 팔레트, 그라디언트 패턴 +- 타이포그래피 위계, 텍스트 스트로크 +- 둥근 모서리 컨테이너 (r:20) +- Badge Header, 2열 비교, N열 카드 레이아웃 구조 + +### 콘텐츠 전용 (블록에 포함하지 않음) +- 3D 화살표 이미지 (Frame 1) → 콘텐츠가 제공 +- 특정 아이콘 이미지들 (brain, thunder 등) → 콘텐츠가 제공 +- 도메인 텍스트 → 슬롯으로 처리 diff --git a/FIGMA-EXTRACTION.md b/FIGMA-EXTRACTION.md new file mode 100644 index 0000000..6592f1c --- /dev/null +++ b/FIGMA-EXTRACTION.md @@ -0,0 +1,441 @@ +# Figma → HTML 블록 변환 프로세스 + +> 2026-04-07 확립. Figma 디자인을 design_agent 블록으로 변환하는 정확한 방법론. + +--- + +## 1. 전체 워크플로우 + +``` +[Step 1] Figma API로 파일 구조 추출 + ↓ +[Step 2] 프레임별 렌더링 이미지(PNG) 다운로드 + ↓ +[Step 3] 노드별 상세 데이터 추출 (좌표, 색상, 폰트, 크기) + ↓ +[Step 4] 디자인 언어 분석 (공통 패턴 vs 콘텐츠 전용 구분) + ↓ +[Step 5] 블록 설계 (슬롯, 동적 규칙, schema) + ↓ +[Step 6] 수학적 계산 (Figma 좌표 → 스케일 → CSS값) + ↓ +[Step 7] HTML/CSS 구현 + ↓ +[Step 8] 비교 리뷰 (Figma PNG vs HTML, 같은 폭으로 위/아래 배치) + ↓ +[Step 9] 피드백 반영 → Step 6~8 반복 + ↓ +[Step 10] Jinja2 템플릿화 + catalog.yaml 등록 +``` + +--- + +## 2. Figma API 사용법 + +### 2.1 파일 구조 가져오기 +```bash +curl -s -H "X-Figma-Token: {TOKEN}" \ + "https://api.figma.com/v1/files/{FILE_KEY}" \ + | python -m json.tool +``` + +### 2.2 특정 노드 상세 데이터 +```bash +curl -s -H "X-Figma-Token: {TOKEN}" \ + "https://api.figma.com/v1/files/{FILE_KEY}/nodes?ids={NODE_IDS}&geometry=paths" +``` + +### 2.3 노드 이미지 렌더링 (PNG) +```bash +curl -s -H "X-Figma-Token: {TOKEN}" \ + "https://api.figma.com/v1/images/{FILE_KEY}?ids={NODE_IDS}&format=png&scale=2" +``` +- `scale=2`: 2배 해상도로 다운로드 (선명도 확보) +- 응답의 `images` 객체에 각 노드 ID별 S3 URL 제공 + +### 2.4 추출해야 하는 핵심 데이터 + +| 데이터 | API 필드 | 용도 | +|-------|---------|------| +| 위치 | `absoluteBoundingBox.x, .y` | 요소 간 관계 계산 | +| 크기 | `absoluteBoundingBox.width, .height` | 스케일 계산 | +| 텍스트 | `characters` | 콘텐츠 확인 | +| 폰트 | `style.fontFamily, .fontSize, .fontWeight` | 타이포그래피 | +| 색상 | `fills[].color` | 색상 팔레트 | +| 테두리 | `strokes[], strokeWeight` | 박스 스타일 | +| 라운드 | `cornerRadius` | border-radius | +| 이미지 | `fills[].imageRef` | 이미지 자산 식별 | + +--- + +## 3. 수학적 계산 (핵심) + +### 3.1 스케일 팩터 + +``` +슬라이드 콘텐츠 폭 = 1280px - padding(40px × 2) = 1200px + +scale = 1200 / figma_frame_width +``` + +| Figma 프레임 | 폭 | 스케일 | +|-------------|-----|--------| +| Frame 2 | 1808px | 0.6637 | +| Frame 3 | 1807px | 0.6641 | +| Frame 4 | 3848px | 0.3118 | + +### 3.2 요소 간 정렬 계산 + +**절대 원칙: Figma 좌표 차이값 → 스케일 적용 → CSS값** + +```python +# 예: 리본 접힘선과 박스 테두리 정렬 +badge_y = 1431 # Figma에서 badge 이미지 top Y +box_y = 1449 # Figma에서 box top Y +fold_offset = box_y - badge_y # = 18px (Figma 기준) + +# 스케일 적용 +fold_offset_css = round(fold_offset * scale) # = 12px (CSS) +``` + +**금지: "좀 더 올려볼게요" 식의 시행착오 px 조정** + +### 3.3 이미지 자산 크기 계산 + +```python +# Figma 원본 크기에 스케일 적용 +ribbon_width_css = round(badge_img_width * scale) +ribbon_height_css = round(badge_img_height * scale) + +# 비율 계산 (CSS에서 width만 지정하면 height는 자동) +aspect_ratio = badge_img_width / badge_img_height +``` + +### 3.4 패딩/여백 계산 + +```python +# 리본이 박스 안에 들어오는 높이 = 리본 전체 높이 - 접힘선 오프셋 +ribbon_inside_box = ribbon_height_css - fold_offset_css + +# 박스 상단 패딩 = 리본 침입 높이 + 여유 +box_padding_top = ribbon_inside_box + 6 # 6px 여유 +``` + +### 3.5 실제 계산 예시 (Frame 2) + +``` +입력 (Figma 원본): + badge 이미지: 508×94px, y=1431 + box: y=1449 + frame width: 1808px + +계산: + scale = 1200/1808 = 0.6637 + ribbon_w = 508 × 0.6637 = 337px + ribbon_h = 94 × 0.6637 = 62px + fold_offset = (1449-1431) × 0.6637 = 12px + ribbon_below_fold = 62 - 12 = 50px + box_padding_top = 50 + 6 = 56px + +CSS 출력: + .ribbon { width: 337px; top: -12px; } + .box { padding-top: 56px; } +``` + +--- + +## 4. 이미지 자산 처리 + +### 4.1 CSS로 만들면 안 되는 것 + +| 요소 | 이유 | 처리 | +|------|------|------| +| 3D 리본/두루마리 | 입체감, 그림자, 곡면 → CSS 불가 | Figma에서 PNG 추출 | +| 복잡한 그라디언트 배경 | 다중 정지점, 비선형 → CSS 근사 불가 | 이미지 사용 | +| 아이콘 이미지 | 디자이너가 만든 고유 자산 | 원본 이미지 사용 | + +### 4.2 CSS로 만들 수 있는 것 + +| 요소 | CSS 구현 | +|------|---------| +| 단색/2색 그라디언트 배경 | `linear-gradient()` | +| 둥근 모서리 테두리 박스 | `border + border-radius` | +| 텍스트 스타일 | `font-size, font-weight, color` | +| 그리드/플렉스 레이아웃 | `display: grid / flex` | +| 구분선 | `border` or `background` | + +### 4.3 이미지 추출 및 저장 + +```bash +# Figma API로 특정 노드 이미지 추출 +curl -s -H "X-Figma-Token: {TOKEN}" \ + "https://api.figma.com/v1/images/{FILE_KEY}?ids={NODE_ID}&format=png&scale=2" + +# 다운로드 → static/figma-assets/ 에 저장 +curl -s -o static/figma-assets/{name}.png "{S3_URL}" +``` + +저장 위치: `static/figma-assets/` + +--- + +## 5. 비교 리뷰 페이지 작성법 + +### 5.1 레이아웃 + +``` +같은 폭으로 위/아래 배치 (좌/우 아님 — 크기 차이 문제) + +┌─ 빨간 테두리 ──────────────┐ +│ Figma Original (PNG) │ +└─────────────────────────────┘ + ─ 구분선 ─ +┌─ 초록 테두리 ──────────────┐ +│ HTML Block │ +└─────────────────────────────┘ +``` + +### 5.2 HTML 스케일링 + +```css +.html-inner { + width: 1280px; /* 슬라이드 원본 크기 */ + transform-origin: top left; + transform: scale(0.74); /* 960px 컨테이너에 맞춤: 960/1280 */ +} +``` + +### 5.3 비교 리뷰 파일 위치 + +`data/figma_ref/comparison.html` + +--- + +## 6. Jinja2 템플릿 변환 규칙 + +### 6.1 고정값 → 변수 + +```html + +정책 달성{{ badge_title }} +Engn. Solution{{ left_title }} +``` + +### 6.2 반복 요소 → 루프 + +```html + +{% for card in cards %} +
{{ card.title }}
+{% endfor %} +``` + +### 6.3 이미지 자산 → 슬롯 + +```html + + +``` + +### 6.4 계산된 CSS → CSS 변수 + +```html + +
+``` + +--- + +## 7. 디자인 언어 vs 콘텐츠 전용 구분 + +### 디자인 언어 (블록에 포함, 재사용 가능) +- 색상 팔레트 (warm 테마: 브라운, 틸, 베이지) +- 타이포그래피 위계 (크기, 굵기 단계) +- 레이아웃 구조 (2열 비교, N열 카드 등) +- 장식 요소 (3D 리본, 둥근 컨테이너) + +### 콘텐츠 전용 (블록에 포함하지 않음) +- 특정 텍스트 ("디지털전환은 사용자...") +- 특정 아이콘 이미지 (brain, thunder 등) +- 도메인 전문 용어 (DfMA, Engn. Solution) + +--- + +## 8. 파일 구조 + +``` +design_agent/ +├── static/figma-assets/ ← Figma에서 추출한 이미지 자산 +│ ├── badge_policy.png (틸 3D 리본) +│ ├── badge_solution.png (빨간 3D 리본) +│ ├── box_policy_container.png +│ └── box_solution_cards.png +├── data/figma_ref/ ← 비교 리뷰용 +│ ├── comparison.html (Figma vs HTML 비교 페이지) +│ ├── frame2_1-5.png (Figma 원본 PNG) +│ ├── frame3_1-35.png +│ └── frame4_1-49.png +├── templates/blocks/cards/ ← 블록 템플릿 +│ ├── hero-icon-cards.html +│ ├── compare-2col-badge.html +│ └── compare-detail-gradient.html +├── FIGMA-DESIGN-LANGUAGE.md ← 디자인 언어 분석 결과 +├── FIGMA-EXTRACTION.md ← 이 문서 +└── PHASE-FIGMA-BLOCKS.md ← 블록 설계 명세 +``` + +--- + +## 9. 고급 레이아웃 패턴 + +### 9.1 좌/우 열 섹션 Y선 정렬 (CSS Grid 행 공유) + +2열 비교에서 좌/우 섹션 제목이 같은 Y선에 있어야 할 때: + +**문제**: 각 열을 독립 flex-column으로 만들면, 좌측 섹션 본문이 길면 우측 다음 섹션이 밀림. +``` +flex-column (잘못): + 좌: [제목1] [긴본문] [제목2] + 우: [제목1] [짧은본문] [제목2] ← 제목2가 좌측과 Y가 다름 +``` + +**해결**: CSS Grid 2열 × N행으로 행을 공유하면 자동 정렬. +```css +.block { + display: grid; + grid-template-columns: 1fr 1fr; /* 2열 */ + grid-template-rows: auto auto auto auto; /* 헤더 + N행 */ +} +``` +``` +Grid (올바름): + [좌 헤더] [우 헤더] ← Row 0 + [좌 섹션1] [우 섹션1] ← Row 1 (행 높이 = max(좌,우)) + [좌 섹션2] [우 섹션2] ← Row 2 (Y선 자동 정렬!) +``` + +**실제 계산 (Frame 4)**: +``` +Figma Y좌표: + Row 1: 좌 1166, 우 1166 → 0px 차이 (이미 정렬) + Row 2: 좌 1529, 우 1467 → 62px 차이 (Grid가 해결) + Row 3: 좌 1845, 우 1845 → 0px 차이 (이미 정렬) +원인: Row 1 좌측에 As-Is→To-Be 구조가 있어서 본문이 62px 더 높음 +``` + +### 9.2 As-Is → To-Be 수평 서브 레이아웃 + +한 섹션 안에서 변환 전/후를 수평 배치할 때: + +```html +
+
+
이전 상태 1
+
이전 상태 2
+
+ → +
+
변환 후 1
+
변환 후 2
+
+
+``` +```css +.asis-tobe { display: flex; align-items: center; gap: 8px; } +.asis, .tobe { flex: 1; } +.arrow { width: 60px; height: auto; flex-shrink: 0; } +``` + +**Figma 좌표로 검증**: +``` +As-Is: x=2737, w=539 +Arrow: x=3375, w=252 +To-Be: x=3687, w=672 +→ 세 요소가 같은 Y(1269)에 수평 배치됨을 좌표로 확인 +``` + +### 9.3 3D 리본/두루마리 배지 정렬 공식 + +리본 이미지의 접힘선(fold-back)이 박스 테두리와 정확히 일치해야 할 때: + +``` +┌── 리본 이미지 ──────────────┐ +│ 접힘 삼각형 (fold) │ ← fold_offset (이미지 top에서) +│ 리본 본체 │ +│ │ +└──────────────────────────────┘ +════════════════════════════════ ← 박스 top border (여기에 fold가 일치해야 함) +┌── 박스 ──────────────────────┐ +│ padding-top = ribbon_below │ +│ 콘텐츠 시작 │ + +계산: + fold_offset = (box_y - badge_y) × scale → CSS: top 값 + ribbon_below = ribbon_height - fold_offset → 박스 안 침입 높이 + box_padding_top = ribbon_below + 여유(6px) → 콘텐츠 겹침 방지 +``` + +**핵심**: 리본을 올리거나 내리는 게 아니라, **박스의 위치를 계산**하는 것. +- `top: -fold_offset` → 리본 접힘선 = 박스 top border +- 리본은 그대로, 박스와의 관계만 수학적으로 결정 + +--- + +## 10. 실수 방지 (Anti-patterns) + +### 10.1 절대 하면 안 되는 것 + +| Anti-pattern | 왜 안 되는지 | 올바른 방법 | +|-------------|------------|-----------| +| px 시행착오 조정 ("좀 더 올려볼게") | 3번 이상 실패, 시간 낭비 | Figma 좌표에서 수학적 계산 | +| 3D 효과를 CSS로 재현 | 평면적이라 품질 차이 심각 | Figma에서 PNG 추출 | +| 비교 리뷰를 좌/우 배치 | 크기 차이로 비교 불가 | 위/아래 같은 폭으로 배치 | +| Jinja2 템플릿을 브라우저에서 직접 열기 | 변수 미렌더, 이미지 경로 깨짐 | comparison.html 또는 FastAPI로 확인 | +| 독립 flex-column으로 2열 비교 | 행 정렬 안 됨 | CSS Grid 행 공유 | +| 느낌으로 폰트/색상 설정 | Figma와 다른 결과물 | Figma API에서 정확한 값 추출 | + +### 10.2 반드시 해야 하는 것 + +| 원칙 | 이유 | +|------|------| +| CSS 주석에 계산 근거 기록 | 나중에 왜 이 값인지 추적 가능 | +| 비교 리뷰 후 진행 | 디자인 차이를 사전에 발견 | +| 이미지 자산은 `static/figma-assets/`에 저장 | FastAPI가 서빙, 경로 일관성 | +| `comparison.html`에 모든 프레임 포함 | 한 페이지에서 전체 리뷰 가능 | +| Figma 노드 ID 기록 | 나중에 업데이트된 디자인 재추출 가능 | + +--- + +## 11. Figma 소스 정보 + +### 현재 등록된 Figma 파일 + +| 항목 | 값 | +|------|---| +| File Key | `9S6LsQyO6zlRxtiqZccOUM` | +| Page | Page 1 (0:1) | +| Frame 2 (hero-icon-cards) | Node `1:5` | +| Frame 3 (compare-2col-badge) | Node `1:35` | +| Frame 4 (compare-detail-gradient) | Node `1:49` | +| Badge (빨간 리본) | Node `1:33` (image 4019) | +| Badge (틸 리본) | Node `1:43` (image 2197) | +| Arrow (As-Is→To-Be) | Node `1:67` (image 2645) | +| Box (빨간 테두리) | Node `1:12` (Rectangle 42894) | +| Box (틸 테두리) | Node `1:37` (Rectangle 42598) | + +--- + +## 12. 체크리스트 + +새 Figma 프레임을 블록으로 변환할 때: + +- [ ] Figma API로 노드 데이터 추출 (좌표, 크기, 색상, 폰트) +- [ ] PNG 렌더링 다운로드 (scale=2) +- [ ] 복잡한 비주얼 요소 식별 → 이미지로 추출 (CSS로 만들지 않음) +- [ ] 스케일 팩터 계산 (1200 / frame_width) +- [ ] 핵심 정렬 포인트 수학적 계산 (좌표 차이 × 스케일) +- [ ] CSS 값 도출 (계산 근거를 주석으로 기록) +- [ ] 비교 리뷰 페이지에 추가 (위/아래 같은 폭) +- [ ] 사용자 피드백 확인 +- [ ] Jinja2 템플릿 변환 (고정값→변수, 반복→루프) +- [ ] catalog.yaml 등록 diff --git a/PHASE-FIGMA-BLOCKS.md b/PHASE-FIGMA-BLOCKS.md new file mode 100644 index 0000000..01503a3 --- /dev/null +++ b/PHASE-FIGMA-BLOCKS.md @@ -0,0 +1,463 @@ +# Phase 2: Figma Block Design Specification + +> 3개 블록 + 2개 서브 컴포넌트 상세 설계 +> 기준: FIGMA-DESIGN-LANGUAGE.md 분석 결과 + +--- + +## Block 1: `hero-icon-cards` + +### 1.1 시각적 구조 + +``` +┌──────────────────────────────────────────────┐ +│ [Hero Statement - 큰 텍스트, 중앙] │ ← zone: header or full-width +│ │ +│ ┌─[Badge Title]─┐ │ +│──────────┤ ├───────────────────│ +│ ┌─────┐ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ +│ │icon │ │ │icon │ │icon │ │icon │ │icon │ │ ← N개 카드 (2~6) +│ │ │ │ │ │ │ │ │ │ │ │ │ +│ │Title│ ╎ │Title│ │Title│ │Title│ │Title│ │ ← 세로 구분선 +│ │(sub)│ │ │(sub)│ │(sub)│ │(sub)│ │(sub)│ │ +│ └─────┘ │ └─────┘ └─────┘ └─────┘ └─────┘ │ +│ └───────────────────────────────────│ +└──────────────────────────────────────────────┘ +``` + +### 1.2 슬롯 정의 + +| 슬롯 | 필수 | 타입 | 설명 | +|------|------|------|------| +| `statement` | O | string | Hero 메시지 (1-2줄) | +| `badge_title` | X | string | 배지 바 텍스트 | +| `cards[]` | O | array | 카드 배열 | +| `cards[].icon` | X | string | 아이콘 이미지 URL 또는 이모지 | +| `cards[].title` | O | string | 영문 또는 주제목 | +| `cards[].subtitle` | X | string | 한국어 부제 | +| `cards[].color` | X | string | 개별 카드 강조색 | + +### 1.3 동적 재구성 규칙 + +#### 그리드 계산 +``` +입력: N = cards.length, W = container_width_px + +N ≤ 5: 1행 N열 + col_count = N + card_width = (W - padding*2 - gap*(N-1)) / N + +N = 6: 1행 6열 (gap 축소) + col_count = 6 + gap = 8px (기본 16px에서 축소) + +N > 6: 2행 + col_count = ceil(N / 2) + row_count = 2 +``` + +#### 폰트 스케일링 +``` +card_width ≥ 200px → title: 20px, subtitle: 14px +card_width ≥ 150px → title: 16px, subtitle: 12px +card_width < 150px → title: 14px, subtitle: 11px +``` + +#### 높이 계산 +``` +hero_height = statement_lines * line_height + padding +badge_height = 44px (고정) +card_area_height = icon_height + title_lines * title_lh + subtitle_lh + padding + - 1행: card_area_height + - 2행: card_area_height * 2 + gap + +total_min_height = hero_height + badge_height + card_area_height + gaps +``` + +### 1.4 catalog.yaml schema + +```yaml +- id: hero-icon-cards + name: 히어로 문구 + 아이콘 카드 + category: cards + template: blocks/cards/hero-icon-cards.html + height_cost: xlarge + min_height_px: 280 + relation_types: [definition, flow] + min_items: 2 + max_items: 6 + visual: > + 상단에 큰 Hero 메시지(24px bold, 중앙) + 배지 바 + + 하단에 N열 아이콘 카드(둥근 흰색 컨테이너, 세로 구분선). + 각 카드는 아이콘 이미지 + 영문 제목(20px/900) + 한국어 부제(14px/500). + when: > + 핵심 목표나 가치를 N개 키워드로 선언할 때. + 각 키워드에 아이콘이나 이미지가 있을 때. + "우리가 추구하는 5가지 가치" 같은 구조. + not_for: > + 비교/대조 구조 → compare-2col-badge. + 상세 설명이 길 때 → card-icon-desc. + 순서/단계 → card-step-vertical 또는 process-horizontal. + purpose_fit: [핵심전달, 가치선언] + zone: full-width-only + slots: + required: [statement, cards[]] + optional: [badge_title, cards[].icon, cards[].subtitle, cards[].color] + schema: + statement: + max_lines: 2 + font_size: 24 + ref_chars: + body: 60 + note: "24px bold, 중앙정렬, 흰색 스트로크" + badge_title: + max_lines: 1 + font_size: 18 + ref_chars: + body: 20 + note: "18px bold white, 배지 바 위" + card_title: + max_lines: 2 + font_size: 20 + ref_chars: + body: 15 + note: "20px black/900, 중앙정렬" + card_subtitle: + max_lines: 1 + font_size: 14 + ref_chars: + body: 10 + note: "14px medium, 한국어 부제" + padding_overhead_px: 60 + padding_h_px: 32 +``` + +--- + +## Block 2: `compare-2col-badge` + +### 2.1 시각적 구조 + +``` +┌──────────────────────────────────────────────┐ +│ ┌─[Badge Title]─┐ │ +│────────────┤ ├─────────────────│ +│ │ +│ ┌── Left Column ──┐ ╎ ┌── Right Column ──┐ │ +│ │ │ ╎ │ │ │ +│ │ [Big Title] │ ╎ │ [Big Title] │ │ +│ │ │ ╎ │ │ │ +│ │ body text... │ ╎ │ body text... │ │ +│ │ body text... │ ╎ │ body text... │ │ +│ │ │ ╎ │ │ │ +│ └──────────────────┘ ╎ └──────────────────┘ │ +│ │ +│ [Optional: Hero Statement] │ +└──────────────────────────────────────────────┘ +``` + +### 2.2 슬롯 정의 + +| 슬롯 | 필수 | 타입 | 설명 | +|------|------|------|------| +| `badge_title` | O | string | 배지 바 텍스트 | +| `left_title` | O | string | 좌측 열 대제목 | +| `left_body` | O | string | 좌측 열 본문 | +| `right_title` | O | string | 우측 열 대제목 | +| `right_body` | O | string | 우측 열 본문 | +| `statement` | X | string | 하단 Hero 메시지 | +| `left_color` | X | string | 좌측 강조색 (기본: --color-teal) | +| `right_color` | X | string | 우측 강조색 (기본: --color-teal) | + +### 2.3 동적 재구성 규칙 + +#### 레이아웃 계산 +``` +container_width = 컨테이너 전체 폭 +padding_h = 32px * 2 + +2열 모드 (기본): + col_width = (container_width - padding_h - divider_gap) / 2 + divider_gap = 32px + +1열 모드 (sidebar zone, 폭 < 500px): + 좌/우가 세로 스택 + col_width = container_width - padding_h +``` + +#### 높이 계산 +``` +badge_height = 44px +left_height = title_height + body_lines * line_height + padding +right_height = title_height + body_lines * line_height + padding +content_height = max(left_height, right_height) +statement_height = statement ? (statement_lines * 28 + 16) : 0 + +total = badge_height + content_height + statement_height + gaps +``` + +#### 텍스트 피팅 +``` +col_width에 따른 body 글자수 제한: + col_width ≥ 500px → ~40자/줄, font: 16px + col_width ≥ 350px → ~28자/줄, font: 14px + col_width < 350px → ~20자/줄, font: 13px +``` + +### 2.4 catalog.yaml schema + +```yaml +- id: compare-2col-badge + name: 배지 헤더 2열 비교 + category: cards + template: blocks/cards/compare-2col-badge.html + height_cost: large + min_height_px: 200 + relation_types: [comparison, contrast] + visual: > + 상단 배지 바(이미지/그라디언트 배경 + 흰색 텍스트) 아래 + 2열 비교 레이아웃. 좌/우 각각 대제목(24px/900) + 본문(16px/700). + 중앙 세로 구분선. 둥근 흰색 컨테이너(r:20). + 선택적 하단 Hero 메시지. + when: > + 두 개념/방법/전략을 나란히 비교할 때. + 배지 헤더로 상위 주제를 명시. + 예: "Engn. Solution vs DfMA", "현재 vs 미래" + not_for: > + 3개 이상 항목 비교 → compare-3col-badge. + 장/단점 목록 → comparison-2col. + 상세 내용이 길고 섹션이 많을 때 → compare-detail-gradient. + purpose_fit: [비교대조, 개념정의] + zone: full-width-only + slots: + required: [badge_title, left_title, left_body, right_title, right_body] + optional: [statement, left_color, right_color] + schema: + badge_title: + max_lines: 1 + font_size: 18 + ref_chars: + body: 15 + note: "18px bold white, 배지 바" + left_title: + max_lines: 1 + font_size: 24 + ref_chars: + body: 15 + note: "24px black/900, 흰색 스트로크" + left_body: + max_lines: 6 + font_size: 16 + ref_chars: + body: 200 + note: "16px/700, 틸 색상" + right_title: + max_lines: 1 + font_size: 24 + ref_chars: + body: 15 + note: "24px black/900, 흰색 스트로크" + right_body: + max_lines: 6 + font_size: 16 + ref_chars: + body: 200 + note: "16px/700, 틸 색상" + statement: + max_lines: 2 + font_size: 20 + ref_chars: + body: 50 + note: "20px bold, 중앙정렬" + padding_overhead_px: 56 + padding_h_px: 32 +``` + +--- + +## Block 3: `compare-detail-gradient` + +### 3.1 시각적 구조 + +``` +┌──────────────────────────────────────────────────────────┐ +│ ┌───── Left Header Bar (gradient) ─────┐┌── Right ─────┐│ +│ │ [Left Column Title] ││ [Right Title] ││ +│ └──────────────────────────────────────┘└───────────────┘│ +│ ┌─────── Left BG (warm) ──────┐┌──── Right BG (teal) ──┐│ +│ │ ││ ││ +│ │ [Section 1 Title] ││ [Section 1 Title] ││ +│ │ • body text ││ • body text ││ +│ │ • body text ││ • body text ││ +│ │ ││ ││ +│ │ [Section 2 Title] ││ [Section 2 Title] ││ +│ │ • body text ││ • body text ││ +│ │ • body text ││ • body text ││ +│ │ ││ ││ +│ │ [Section N Title] ││ [Section M Title] ││ +│ │ • body text ││ • body text ││ +│ └──────────────────────────────┘└───────────────────────┘│ +└──────────────────────────────────────────────────────────┘ +``` + +### 3.2 슬롯 정의 + +| 슬롯 | 필수 | 타입 | 설명 | +|------|------|------|------| +| `left_header` | O | string | 좌측 열 헤더 타이틀 | +| `right_header` | O | string | 우측 열 헤더 타이틀 | +| `left_sections[]` | O | array | 좌측 섹션 배열 | +| `left_sections[].title` | O | string | 섹션 소제목 | +| `left_sections[].body` | O | string | 섹션 본문 (줄바꿈 허용) | +| `right_sections[]` | O | array | 우측 섹션 배열 | +| `right_sections[].title` | O | string | 섹션 소제목 | +| `right_sections[].body` | O | string | 섹션 본문 | +| `left_color_theme` | X | string | 좌측 테마 (기본: warm) | +| `right_color_theme` | X | string | 우측 테마 (기본: teal) | + +### 3.3 동적 재구성 규칙 (★ 가장 수학적으로 복잡) + +#### 그리드 계산 +``` +container_width에서 2열 분할: + col_width = (container_width - gap) / 2 + gap = 0px (그라디언트가 맞닿음) +``` + +#### 섹션 높이 계산 (핵심) +``` +header_bar_height = 48px (고정) + +각 섹션의 높이: + section_height(s) = + title_height(s.title, title_font_size, col_width) + + body_height(s.body, body_font_size, col_width) + + section_padding + + title_height = ceil(char_count / chars_per_line) * title_line_height + body_height = line_count * body_line_height + + chars_per_line = floor(col_width / (font_size * 0.55)) // 한글 평균 0.55em + +좌측 전체: + left_total = header_bar + sum(section_height for s in left_sections) + gaps + +우측 전체: + right_total = header_bar + sum(section_height for s in right_sections) + gaps + +content_height = max(left_total, right_total) +``` + +#### 오버플로 방지 — Fit 검증 +``` +if content_height > container_available_height: + + 전략 1: 폰트 축소 + body_font_size -= 1px (최소 12px) + 재계산 + + 전략 2: 섹션 본문 줄 수 제한 + max_body_lines = floor( + (available_per_section - title_height) / body_line_height + ) + available_per_section = (container_height - header*2 - gaps) / max(N_left, N_right) + + 전략 3: Kei 에스컬레이션 (기존 파이프라인) + content 요약 요청 +``` + +#### 색상 테마 매핑 +``` +warm (좌측 기본): + header_gradient: rgba(165,161,150,0.10) → rgba(57,50,30,1.00) + section_title_color: var(--color-warm-brown) + bg: rgba(255,255,255,0.30) → rgba(57,50,30,0.30) + +teal (우측 기본): + header_gradient: rgba(41,107,85,0.10) → rgba(3,33,24,1.00) + section_title_color: var(--color-dark-teal) + bg: rgba(41,107,85,0.30) → rgba(255,255,255,0.30) +``` + +### 3.4 catalog.yaml schema + +```yaml +- id: compare-detail-gradient + name: 그라디언트 상세 2열 비교 + category: cards + template: blocks/cards/compare-detail-gradient.html + height_cost: xlarge + min_height_px: 300 + relation_types: [comparison, contrast, process] + min_items: 2 # 좌/우 최소 1섹션씩 + max_items: 10 # 좌+우 합계 + visual: > + 좌우 그라디언트 배경(워 브라운 vs 다크틸)으로 나뉜 2열 비교. + 각 열 상단에 그라디언트 헤더 바 + 큰 제목(28px/900). + 하단에 N개 섹션(소제목 22px/900 + 본문 16px/700) 반복. + 좌측은 따뜻한 톤(과정/As-Is), 우측은 차가운 톤(결과/To-Be). + when: > + 두 카테고리를 상세하게 비교할 때. + 각 카테고리에 여러 하위 항목이 있을 때. + 과정 vs 결과, As-Is vs To-Be, 문제 vs 해결 구조. + not_for: > + 간단한 2항목 비교(본문 짧을 때) → compare-2col-badge. + 3열 비교 → compare-3col-badge. + 비교가 아닌 단독 리스트 → dark-bullet-list. + purpose_fit: [비교대조, 구조시각화, 근거사례] + zone: full-width-only + slots: + required: [left_header, right_header, left_sections[], right_sections[]] + optional: [left_color_theme, right_color_theme] + schema: + left_header: + max_lines: 1 + font_size: 28 + ref_chars: + body: 20 + note: "28px black/900, 그라디언트 바 위" + right_header: + max_lines: 1 + font_size: 28 + ref_chars: + body: 20 + note: "28px black/900, 그라디언트 바 위" + section_title: + max_lines: 2 + font_size: 22 + ref_chars: + body: 30 + note: "22px/900, 색상 테마별 (브라운 or 틸)" + section_body: + max_lines: 4 + font_size: 16 + ref_chars: + body: 120 + note: "16px/700, black" + padding_overhead_px: 48 + padding_h_px: 0 +``` + +--- + +## 서브 컴포넌트 + +### S1. 장식 이미지 (3D 화살표 등) +- 블록이 아닌 **콘텐츠 이미지**로 처리 +- `cards[].icon` 또는 별도 `decoration_image` 슬롯으로 전달 +- 블록은 `` 태그로 렌더링, 크기는 CSS로 컨테이너에 맞춤 + +### S2. CTA 버튼 +- 독립 블록이 아닌 **다른 블록 내 선택적 요소** +- `cta_text` 슬롯으로 전달 (없으면 미표시) +- CSS: 그라디언트 바 + 둥근 버튼 (r:7) + +--- + +## 구현 우선순위 + +| 순서 | 블록 | 이유 | +|------|------|------| +| 1 (파일럿) | `compare-2col-badge` | 중간 복잡도, 기존 compare-2col-split과 비교 검증 가능 | +| 2 | `hero-icon-cards` | N개 카드 그리드 계산 필요, 파일럿 경험 활용 | +| 3 | `compare-detail-gradient` | 가장 복잡 (N개 섹션 × 2열, 높이 균형, 오버플로 방지) | diff --git a/scripts/figma_to_html.py b/scripts/figma_to_html.py new file mode 100644 index 0000000..e26a7c7 --- /dev/null +++ b/scripts/figma_to_html.py @@ -0,0 +1,261 @@ +"""Figma 프레임을 HTML/CSS로 변환. + +기존 블록 템플릿(templates/blocks/)과 동일한 방식으로 +Figma API 데이터에서 정확한 HTML을 생성한다. + +Usage: + python scripts/figma_to_html.py data/runs/figma_beps_full.json templates/blocks/BEPs/ +""" +from __future__ import annotations +import json +import math +import sys +from pathlib import Path + + +def get_fill_css(fills: list[dict]) -> tuple[str, str]: + """fills 배열에서 CSS background와 color를 추출. + + Returns: (background_css, color_css) + """ + bg = "" + color = "" + for f in fills: + if not f.get("visible", True): + continue + ftype = f.get("type", "") + if ftype == "SOLID": + c = f["color"] + r, g, b = int(c["r"] * 255), int(c["g"] * 255), int(c["b"] * 255) + a = f.get("opacity", c.get("a", 1)) + if a < 0.99: + val = f"rgba({r},{g},{b},{a:.2f})" + else: + val = f"#{r:02x}{g:02x}{b:02x}" + bg = val + color = val + elif "GRADIENT" in ftype: + stops = f.get("gradientStops", []) + handles = f.get("gradientHandlePositions", []) + if len(stops) < 2: + continue + # 각도 계산 + if len(handles) >= 2: + dx = handles[1]["x"] - handles[0]["x"] + dy = handles[1]["y"] - handles[0]["y"] + angle = math.degrees(math.atan2(dy, dx)) + 90 + else: + angle = 180 + stop_str = ",".join( + f"#{int(s['color']['r']*255):02x}{int(s['color']['g']*255):02x}{int(s['color']['b']*255):02x} {s['position']*100:.0f}%" + for s in stops + ) + bg = f"linear-gradient({angle:.0f}deg,{stop_str})" + color = bg + elif ftype == "IMAGE": + bg = "__IMAGE__" + return bg, color + + +def node_to_html(node: dict, ox: float, oy: float, scale: float) -> str: + """단일 노드를 HTML div로 변환.""" + ntype = node.get("type", "") + name = node.get("name", "") + bb = node.get("absoluteBoundingBox") + if not bb or not bb.get("width"): + return "" + + x = (bb["x"] - ox) * scale + y = (bb["y"] - oy) * scale + w = bb["width"] * scale + h = bb["height"] * scale + + fills = node.get("fills", []) + visible_fills = [f for f in fills if f.get("visible", True)] + + if ntype == "TEXT": + chars = node.get("characters", "") + if not chars: + return "" + style = node.get("style", {}) + fs = style.get("fontSize", 12) * scale + fw = style.get("fontWeight", 400) + align_h = style.get("textAlignHorizontal", "LEFT").lower() + align_v = style.get("textAlignVertical", "TOP") + lh_px = style.get("lineHeightPx", 0) + lh = lh_px * scale if lh_px else fs * 1.5 + ls = style.get("letterSpacing", 0) * scale + + # 텍스트 fill 처리 + has_gradient = any( + "GRADIENT" in f.get("type", "") for f in visible_fills + ) + if has_gradient: + bg, _ = get_fill_css( + [f for f in visible_fills if "GRADIENT" in f.get("type", "")] + ) + text_style = ( + f"background:{bg};" + f"-webkit-background-clip:text;" + f"-webkit-text-fill-color:transparent;" + ) + else: + _, c = get_fill_css(visible_fills) + text_style = f"color:{c or '#000'};" + + lh_css = f"line-height:{lh:.1f}px;" + ls_css = f"letter-spacing:{ls:.1f}px;" if ls > 0.1 else "" + align_css = f"text-align:{align_h};" if align_h != "left" else "" + valign_css = ( + "display:flex;align-items:center;" if align_v == "CENTER" else "" + ) + + text_html = chars.replace("\n", "
") + return ( + f'
{text_html}
' + ) + + elif ntype in ("RECTANGLE", "VECTOR"): + bg, _ = get_fill_css(visible_fills) + if not bg: + return "" + if bg == "__IMAGE__": + # 이미지 placeholder + return ( + f'
' + ) + + cr = node.get("cornerRadius", 0) + cr_css = f"border-radius:{cr * scale:.1f}px;" if cr > 0 else "" + + strokes = node.get("strokes", []) + stroke_css = "" + if strokes: + for s in strokes: + if not s.get("visible", True): + continue + sc = s.get("color", {}) + sr = int(sc.get("r", 0) * 255) + sg = int(sc.get("g", 0) * 255) + sb = int(sc.get("b", 0) * 255) + sw = node.get("strokeWeight", 1) * scale + stroke_css = ( + f"border:{sw:.1f}px solid #{sr:02x}{sg:02x}{sb:02x};" + ) + break + + return ( + f'
' + ) + + return "" + + +def frame_to_html(frame: dict, target_width: int = 1280) -> str: + """프레임 전체를 HTML 문서로 변환.""" + bb = frame.get("absoluteBoundingBox", {}) + ox, oy = bb["x"], bb["y"] + fw, fh = bb["width"], bb["height"] + scale = target_width / fw + out_h = int(fh * scale) + + # 모든 리프 노드 수집 (재귀) + elements: list[tuple[int, str]] = [] # (z-order, html) + + def collect(node: dict, z: int = 0): + ntype = node.get("type", "") + children = node.get("children", []) + + if ntype in ("GROUP", "FRAME", "CANVAS", "COMPONENT", "INSTANCE"): + # 컨테이너는 자식만 순회 + for i, child in enumerate(children): + collect(child, z + i) + else: + html = node_to_html(node, ox, oy, scale) + if html: + elements.append((z, html)) + for i, child in enumerate(children): + collect(child, z + i) + + collect(frame, 0) + + # 프레임 배경 + frame_fills = frame.get("fills", []) + frame_bg, _ = get_fill_css( + [f for f in frame_fills if f.get("visible", True)] + ) + frame_bg_css = f"background:{frame_bg};" if frame_bg else "background:#fff;" + + # z-order 순으로 정렬 (rect 먼저, text 나중) + rects = [(z, h) for z, h in elements if "font-size" not in h] + texts = [(z, h) for z, h in elements if "font-size" in h] + + parts = [ + f""" + +
""" + ] + + # rect를 먼저 (배경), text를 나중 (전경) + for _, h in sorted(rects, key=lambda x: x[0]): + parts.append(h) + for _, h in sorted(texts, key=lambda x: x[0]): + parts.append(h) + + parts.append("
") + return "\n".join(parts) + + +def main(): + if len(sys.argv) < 3: + print( + "Usage: python scripts/figma_to_html.py " + ) + sys.exit(1) + + figma_json = Path(sys.argv[1]) + output_dir = Path(sys.argv[2]) + output_dir.mkdir(parents=True, exist_ok=True) + + data = json.loads(figma_json.read_text(encoding="utf-8")) + doc = data.get("document", {}) + pages = doc.get("children", []) + + for page in pages: + for i, frame in enumerate(page.get("children", [])): + if frame.get("type") not in ("FRAME", "COMPONENT"): + continue + name = frame.get("name", f"frame_{i}") + # 파일명 정리 + safe_name = ( + name.replace(" ", "_") + .replace("/", "_") + .replace("\\", "_") + ) + html = frame_to_html(frame) + out_path = output_dir / f"{safe_name}.html" + out_path.write_text(html, encoding="utf-8") + bb = frame.get("absoluteBoundingBox", {}) + print( + f" {safe_name}.html" + f" ({bb.get('width', 0):.0f}x{bb.get('height', 0):.0f}" + f" -> 1280px)" + ) + + print(f"\n완료: {output_dir}") + + +if __name__ == "__main__": + main() diff --git a/static/figma-assets/arrow_asis_tobe.png b/static/figma-assets/arrow_asis_tobe.png new file mode 100644 index 0000000..554b6af Binary files /dev/null and b/static/figma-assets/arrow_asis_tobe.png differ diff --git a/static/figma-assets/badge_policy.png b/static/figma-assets/badge_policy.png new file mode 100644 index 0000000..c12821a Binary files /dev/null and b/static/figma-assets/badge_policy.png differ diff --git a/static/figma-assets/badge_solution.png b/static/figma-assets/badge_solution.png new file mode 100644 index 0000000..022aaaf Binary files /dev/null and b/static/figma-assets/badge_solution.png differ diff --git a/static/figma-assets/box_policy_container.png b/static/figma-assets/box_policy_container.png new file mode 100644 index 0000000..2983a64 Binary files /dev/null and b/static/figma-assets/box_policy_container.png differ diff --git a/static/figma-assets/box_solution_cards.png b/static/figma-assets/box_solution_cards.png new file mode 100644 index 0000000..a986465 Binary files /dev/null and b/static/figma-assets/box_solution_cards.png differ diff --git a/static/tokens.css b/static/tokens.css index ae3f60c..c1656b5 100644 --- a/static/tokens.css +++ b/static/tokens.css @@ -34,6 +34,14 @@ --spacing-inner: 16px; --spacing-small: 8px; + /* Warm 테마 (Figma 2026-04) */ + --color-warm-brown: #5C3714; + --color-dark-teal: #084C56; + --color-teal: #227582; + --color-forest: #548235; + --color-beige: #E4D9C0; + --color-warm-yellow: #FAEDCB; + /* 기타 */ --radius: 6px; --border-width: 1px; diff --git a/templates/blocks/BEPs/detail-button.html b/templates/blocks/BEPs/detail-button.html new file mode 100644 index 0000000..fbc56e7 --- /dev/null +++ b/templates/blocks/BEPs/detail-button.html @@ -0,0 +1,29 @@ + + +
+ {{ label | default('상세보기') }} +
+ + diff --git a/templates/blocks/BEPs/engn-solution-dfma.html b/templates/blocks/BEPs/engn-solution-dfma.html new file mode 100644 index 0000000..539d3a9 --- /dev/null +++ b/templates/blocks/BEPs/engn-solution-dfma.html @@ -0,0 +1,73 @@ + + +
+
+ {% for item in items %} +
+
{{ item.title }}
+
{{ item.description }}
+
+ {% endfor %} +
+ {% if main_text %} +
{{ main_text }}
+ {% endif %} + {% if policy_label %} +
{{ policy_label }}
+ {% endif %} +
+ + diff --git a/templates/blocks/BEPs/image-placeholder.html b/templates/blocks/BEPs/image-placeholder.html new file mode 100644 index 0000000..4efba3e --- /dev/null +++ b/templates/blocks/BEPs/image-placeholder.html @@ -0,0 +1,25 @@ + + +
+ {{ alt | default('') }} +
+ + diff --git a/templates/blocks/BEPs/policy-direction.html b/templates/blocks/BEPs/policy-direction.html new file mode 100644 index 0000000..3615b34 --- /dev/null +++ b/templates/blocks/BEPs/policy-direction.html @@ -0,0 +1,87 @@ + + +
+
+
{{ title }}
+ {% if description %} +
{{ description }}
+ {% endif %} +
+
+ {% for section in sub_sections %} +
+
{{ section.title }}
+ {% for bullet in section.bullets %} +
• {{ bullet }}
+ {% endfor %} +
+ {% endfor %} +
+ {% if questions %} +
+ {% for q in questions %} +
{{ q.text }}
+ {% endfor %} +
+ {% endif %} +
+ + diff --git a/templates/blocks/BEPs/process-product-2col.html b/templates/blocks/BEPs/process-product-2col.html new file mode 100644 index 0000000..87d7c33 --- /dev/null +++ b/templates/blocks/BEPs/process-product-2col.html @@ -0,0 +1,187 @@ + + +
+
+
+ {{ left_title }} +
+
+ {% if left_compare %} +
{{ left_compare.title }}
+
+
+ {% for item in left_compare.left_items %} +
• {{ item }}
+ {% endfor %} +
+
+ → +
+
+ {% for item in left_compare.right_items %} +
• {{ item }}
+ {% endfor %} +
+
+ {% endif %} + {% for section in left_sections %} +
{{ section.title }}
+ {% for bullet in section.bullets %} +
• {{ bullet }}
+ {% endfor %} + {% endfor %} +
+
+
+
+ {{ right_title }} +
+
+ {% for section in right_sections %} +
{{ section.title }}
+ {% for bullet in section.bullets %} +
• {{ bullet }}
+ {% endfor %} + {% endfor %} +
+
+
+ + diff --git a/templates/blocks/BEPs/process-product-2col.svg b/templates/blocks/BEPs/process-product-2col.svg new file mode 100644 index 0000000..285e96a --- /dev/null +++ b/templates/blocks/BEPs/process-product-2col.svg @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/blocks/BEPs/process-product-2col_svg_test.html b/templates/blocks/BEPs/process-product-2col_svg_test.html new file mode 100644 index 0000000..6416aee --- /dev/null +++ b/templates/blocks/BEPs/process-product-2col_svg_test.html @@ -0,0 +1,198 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ \ No newline at end of file diff --git a/templates/blocks/BEPs/process-product-2col_test.html b/templates/blocks/BEPs/process-product-2col_test.html new file mode 100644 index 0000000..4bf085b --- /dev/null +++ b/templates/blocks/BEPs/process-product-2col_test.html @@ -0,0 +1,141 @@ + + + +
+
+
+ 과정 (Process)의 혁신 +
+
+
Analogue 개념 기반 업무의 Digital Transformation
+
+
+
• 개념, 도서, 행정 절차 중심
+
• 2D 도면, 전문가, 규정
+
• 업무 구분(단절), 책임
+
+
+
+
• 시각화된 목적물, 소통, 투명성 중심
+
• 3D 모델, 참여자, 실체
+
• 협업(융·복합), 창의성
+
+
+
위치기반의 3D 모델을 사용하는 Process 혁신
+
• 위치기반(지리적, 지형, 지반상태 포함)의 GIS와 3D 모델(형상, 내용속성) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신
+
사용자 중심의 Solution(S/W) 제공
+
• 인프라 건설산업의 1차적인 Process 혁신은 등고선 중심의 지형도가 아닌 속성이 포함된 수치지형도와 본태 측량에서 획득한 3D 지반모델 구축 필수
+
• 설계와 시공에 관련된 기술을 정리하고 디지털화하여 S/W로 기술 축적
+
• 서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계가 가능하도록 설계, 시공 Solution 제공
+
+
+
+
+ 결과 (Products)의 혁신 +
+
+
Copy & Paste로 인한 하향 평준화된 기존 성과품의 품질 향상
+
• 과거 수작업으로 시행하면서 발생하던 오류 등의 최소화
+
• 정확한 Data에 기반한 계획과 개선된 높은 품질의 성과물
+
Analogue 기반 도서 외 Digital 기반 정보물 추가
+
• 규정에만 의존한 도면, 수량, 계산서, 시방서 등의 성과물에 3D 모델, 시뮬레이션 등의 Digital 기반 정보물(Information Data and Products)이 추가
+
Solution을 이용한 업무효율화(사용자 편의, 협업 및 의사소통 강화 등)
+
• 디지털 기반 성과물인 Graphic 중심의 3D 모델, 시뮬레이션을 제대로 활용하기 위해서는 기존의 낮은 수준이 아니라 공학용 사이니지(H/W) 시스템이 필수로 갖춰야만 함
+
• Engn. Solution을 통해 프로젝트에 관한 이슈를 함께 검토하고 논의하고 다양한 건설단계별 정보를 디지털 데이터로 저장하여 건설의 전 과정을 통합관리
+
+
+
+ + diff --git a/templates/blocks/BEPs/solution-goals.html b/templates/blocks/BEPs/solution-goals.html new file mode 100644 index 0000000..eafbe87 --- /dev/null +++ b/templates/blocks/BEPs/solution-goals.html @@ -0,0 +1,76 @@ + + +
+
Solution 제작 목표
+
{{ main_text }}
+
+ {% for g in goals %} +
+ {% if g.icon %}{{ g.en }}{% endif %} +
{{ g.en }}
+
{{ g.ko }}
+
+ {% endfor %} +
+
+ + diff --git a/templates/blocks/cards/compare-2col-badge.html b/templates/blocks/cards/compare-2col-badge.html new file mode 100644 index 0000000..b464c45 --- /dev/null +++ b/templates/blocks/cards/compare-2col-badge.html @@ -0,0 +1,106 @@ + + +
+
+ {% if badge_title %} +
+ + {{ badge_title }} +
+ {% endif %} + +
+
+
+ {{ left_title }} +
+
+ {{ left_body }} +
+
+ +
+ +
+
+ {{ right_title }} +
+
+ {{ right_body }} +
+
+
+
+ + {% if statement %} +
{{ statement }}
+ {% endif %} +
+ + diff --git a/templates/blocks/cards/compare-detail-gradient.html b/templates/blocks/cards/compare-detail-gradient.html new file mode 100644 index 0000000..87ef7e5 --- /dev/null +++ b/templates/blocks/cards/compare-detail-gradient.html @@ -0,0 +1,113 @@ + + +
+ +
+ {{ left_header }} +
+
+ {{ right_header }} +
+ + + {% for row in sections %} +
+
{{ row.left.title }}
+ {% if row.left.asis is defined %} +
+
+ {% for b in row.left.asis %}
{{ b }}
{% endfor %} +
+ → +
+ {% for b in row.left.tobe %}
{{ b }}
{% endfor %} +
+
+ {% elif row.left.bullets is defined %} +
+ {% for b in row.left.bullets %}
{{ b }}
{% endfor %} +
+ {% else %} +
{{ row.left.body }}
+ {% endif %} +
+ +
+
{{ row.right.title }}
+ {% if row.right.bullets is defined %} +
+ {% for b in row.right.bullets %}
{{ b }}
{% endfor %} +
+ {% else %} +
{{ row.right.body }}
+ {% endif %} +
+ {% endfor %} +
+ + diff --git a/templates/blocks/cards/hero-icon-cards.html b/templates/blocks/cards/hero-icon-cards.html new file mode 100644 index 0000000..4088792 --- /dev/null +++ b/templates/blocks/cards/hero-icon-cards.html @@ -0,0 +1,98 @@ + + +
+ {% if statement %} +
{{ statement }}
+ {% endif %} + +
+ {% if badge_title %} +
+ + {{ badge_title }} +
+ {% endif %} + +
+
+ {% for card in cards %} +
+ {% if card.icon %}
{{ card.icon }}
{% endif %} +
{{ card.title }}
+ {% if card.subtitle %}
({{ card.subtitle }})
{% endif %} +
+ {% if not loop.last %}
{% endif %} + {% endfor %} +
+
+
+
+ + diff --git a/templates/blocks/cards/hero-icon-cards_1.html b/templates/blocks/cards/hero-icon-cards_1.html new file mode 100644 index 0000000..616b22d --- /dev/null +++ b/templates/blocks/cards/hero-icon-cards_1.html @@ -0,0 +1,111 @@ + + +
+ {% if statement %} +
{{ statement }}
+ {% endif %} + +
+ {% if badge_title %} +
+ + {{ badge_title }} +
+ {% endif %} + +
+
+ {% for card in cards %} +
+
{{ card.title }}
+ {% for section in card.sections %} +
{{ section.title }}
+ {% for bullet in section.bullets %} +
{{ bullet }}
+ {% endfor %} + {% endfor %} +
+ {% if not loop.last %}
{% endif %} + {% endfor %} +
+
+
+
+ + diff --git a/templates/blocks/cards/test-compare-2col-badge.html b/templates/blocks/cards/test-compare-2col-badge.html new file mode 100644 index 0000000..dfc4fdc --- /dev/null +++ b/templates/blocks/cards/test-compare-2col-badge.html @@ -0,0 +1,169 @@ + + + + + +compare-2col-badge 테스트 + + + + + + +

Test 1: Figma Frame 3 원본 (Engn. Solution vs DfMA)

+
+ + +
+
+ 정책 달성 +
+
+
+
Engn. Solution
+
목적 시설물에 대한 설계, 시공, 유지관리 정보를 고객이 쉽고 편리하게 사용하고, 편익이 발생하도록 제공하는 다양한 형태의 정보물과 이를 구현할 수 있는 S/W 및 H/W와 그 기술을 포함하는 서비스
+
+
+
+
DfMA
+
Design for Manufacture and Assembly는 공장 생산, 현장조립이 가능한 설계를 의미하며, 현장 중심의 건설에서 공장 생산 방식으로 전환하는 OSC(Off Site Construction) 시스템을 위한 핵심기술
+
+
+
디지털전환은 사용자(발주자, 수급자, 엔지니어)가
쉽고, 편하고, 편익이 있어야만 한다.
+
+ + +
+ +

Test 2: 다른 콘텐츠 (범용성 확인)

+
+ +
+
+ 디지털 전환 전략 +
+
+
+
As-Is (현재)
+
종이 도면 기반의 업무 프로세스 +수작업 검증과 품질 관리 +분절된 단계별 정보 전달 +개인 경험에 의존하는 의사결정
+
+
+
+
To-Be (미래)
+
3D 모델 기반의 통합 프로세스 +자동화된 검증과 품질 관리 +연속적인 디지털 정보 흐름 +데이터 기반의 의사결정 지원
+
+
+
+ +
+ +

Test 3: 짧은 콘텐츠 (최소 케이스)

+
+ +
+
+ 비교 +
+
+
+
BIM
+
건축정보모델링
+
+
+
+
GIS
+
지리정보시스템
+
+
+
+ +
+ + + + + + diff --git a/templates/blocks/cards/test-compare-detail-gradient_1.html b/templates/blocks/cards/test-compare-detail-gradient_1.html new file mode 100644 index 0000000..c9fc13b --- /dev/null +++ b/templates/blocks/cards/test-compare-detail-gradient_1.html @@ -0,0 +1,149 @@ + + +
+ + +
+ +
+ 과정 (Process)의 혁신 +
+
+ 결과 (Products)의 변화 +
+ + + +
+
Analogue 기반 업무의 Digital Transformation
+ +
+
+
개념·문서·행정 절차 중심
2D 도면, 전문가, 규정
업무 구분(단절), 책임
+
+ → +
+
시각화된 목적물, 소통, 투명성 중심
3D 모델, 참여자, 실체
협업(융·복합), 창의성
+
+
+ +
+ +
+
Copy & Paste로 인한 하향 평준화된 기존 성과물의 품질 향상
+ +
+
과거 수작업으로 시행하면서 발생하던 오류 등의 최소화
정확한 Data에 기반한 계획으로 고품질 성과물 도출
+
+ +
+ +
+
위치기반의 3D 모델을 사용하는 Process 혁신
+ +
+
지리·지형·지반 등 위치정보(GIS)와 3D모델(형상, 속성정보) 기반의 건설 정보를 포함하는 BIM의 연계를 통한 업무 프로세스의 혁신
+
+ +
+ +
+
Analogue 기반 도서 외 Digital 기반 정보물 추가
+ +
+
기존 성과물(도면, 수량, 계산서, 시방서 등)에 3D 모델, Simulation 등의 Digital 기반 정보물 추가
+
+ +
+ +
+
사용자 중심의 Solution(S/W) 제공
+ +
+
서로 다른 S/W로 작성되어 분절화된 Analogue 방식의 성과물과 정보물을 연계할 수 있는 설계·시공 Solution 제공
+
+ +
+ +
+
Solution을 활용한 업무 효율화
+ +
+
Engn. Solution을 통해 성과물에 관한 이슈를 함께 검토·논의하는 협업 환경 조성
건설 단계별 정보를 디지털 데이터로 축적하여, 건설 전 과정을 통합관리
+
+ +
+ +
+ + +
+ \ No newline at end of file diff --git a/templates/blocks/cards/test-hero-icon-cards_1.html b/templates/blocks/cards/test-hero-icon-cards_1.html new file mode 100644 index 0000000..7346b5b --- /dev/null +++ b/templates/blocks/cards/test-hero-icon-cards_1.html @@ -0,0 +1,162 @@ + + +
+ + +
+ + +
+ +
+ + DX 시행을 위한 필수 요건 +
+ + +
+
+ +
+
기술(디지털)
+ +
Digital 기술(S/W, H/W)과 업무 Process의 통합
+ +
기존 업무 프로세스에 다양한 디지털 기술을 접목하여 업무 수행
+ +
프로젝트 전반에 걸친 업무 프로세스의 연결 및 조율
+ + +
분야별 전문 지식(설계, 시공, 유지관리 등) 보유
+ +
건설 전 단계에 대한 근본적인 이해와 지식 및 경험
+ +
최신 토목 기술 트랜드 및 표준 기준 등에 대한 높은 지식
+ + +
+
+ +
+
사람(역량)
+ +
혁신적 사고방식과 창의적 문제 해결 능력
+ +
기존 수행 방식과 관습적 사고 등에 의한 접근 방식 탈피
+ +
디지털 기술을 활용한 창의적, 혁신적인 솔루션 제시
+ + +
사용자 중심 사고와 DX 수행 경험
+ +
사용자의 요구와 기대를 충족시키는 설계 및 구현
+ +
시행착오를 포함한 수행 경험과 사용자 경험(UX)을 반영한 해결 방안 제시
+ + +
+
+ +
+
자연(여건)
+ +
지속적인 투자 및 실행 의지
+ +
기술 도입 초기 단계에 필요한 인력·기간·비용 등의 대규모 투자
+ +
기술 고도화를 위한 지속적인 개선 및 투자 체계 구축
+ +
변화와 혁신을 통해 부가가치를 창출하려는 실행 의지와 추진력
+ + +
+ + +
+
+
+
+ + +
+ \ No newline at end of file diff --git a/templates/blocks/cards/test-hero-icon-cards_1.png b/templates/blocks/cards/test-hero-icon-cards_1.png new file mode 100644 index 0000000..4f9fd34 Binary files /dev/null and b/templates/blocks/cards/test-hero-icon-cards_1.png differ diff --git a/templates/catalog.yaml b/templates/catalog.yaml index c5de5a7..3a4fd06 100644 --- a/templates/catalog.yaml +++ b/templates/catalog.yaml @@ -751,6 +751,227 @@ blocks: note: 항목 수 padding_overhead_px: 22 padding_h_px: 32 +- id: hero-icon-cards + name: 히어로 문구 + 아이콘 카드 + category: cards + template: blocks/cards/hero-icon-cards.html + height_cost: xlarge + min_height_px: 280 + relation_types: + - definition + - flow + min_items: 2 + max_items: 6 + visual: > + 다크 배경. 상단 큰 Hero 메시지(28px bold, 중앙, 흰 텍스트, 빨간 강조). + 3D 빨간 리본 배지가 빨간 테두리 흰 박스(r:20) 위에 걸침. + 박스 안에 N열 아이콘 카드(구분선). 각 카드: 아이콘 + 영문 제목(20px/900) + 한국어 부제(15px/500). + visual_diff: > + - card-icon-desc: 밝은 배경, 이모지+제목+설명. 리본/테두리 없음. + - card-dark-overlay: 다크 배경 이미지+흰 텍스트. 카드 개별 배경. + - 이 블록: 다크 배경 + 빨간 리본 배지 + 빨간 테두리 흰 박스 안 N열 카드. + 적합: 핵심 목표/가치를 N개 키워드로 선언하며 시각적 임팩트 필요할 때. + 부적합: 상세 설명 → card-icon-desc, 비교 → compare-2col-badge. + when: > + 핵심 목표나 가치를 N개 키워드로 선언할 때. + 각 키워드에 아이콘이나 이미지가 있을 때. + 프레젠테이션형 임팩트가 필요할 때. + not_for: > + 비교/대조 → compare-2col-badge. + 상세 설명 → card-icon-desc. + 순서/단계 → process-horizontal. + purpose_fit: + - 핵심전달 + zone: full-width-only + slots: + required: + - statement + - cards[] + optional: + - badge_title + - ribbon_image + - cards[].icon + - cards[].subtitle + schema: + statement: + max_lines: 2 + font_size: 28 + ref_chars: + body: 60 + note: "28px bold white, 중앙, em=빨간 강조" + badge_title: + max_lines: 1 + font_size: 20 + ref_chars: + body: 15 + note: "20px bold white, 3D 리본 위" + card_title: + max_lines: 2 + font_size: 20 + ref_chars: + body: 15 + note: "20px black/900, 중앙정렬" + card_subtitle: + max_lines: 1 + font_size: 15 + ref_chars: + body: 10 + note: "15px medium, 한국어 부제" + padding_overhead_px: 80 + padding_h_px: 32 +- id: compare-detail-gradient + name: 그라디언트 상세 2열 비교 + category: cards + template: blocks/cards/compare-detail-gradient.html + height_cost: xlarge + min_height_px: 300 + relation_types: + - comparison + - contrast + - process + min_items: 2 + max_items: 10 + visual: > + 좌우 그라디언트 배경(워 브라운 vs 다크틸)으로 나뉜 2열 비교. + 비대칭 라운드 헤더(좌: 우라운드+우정렬, 우: 좌라운드+좌정렬). + N개 섹션(소제목 18px/900 + 불릿 14px/700) 반복. + CSS Grid 행 공유로 좌/우 섹션 제목이 같은 Y선에 정렬. + 첫 섹션에 As-Is → 화살표 → To-Be 수평 배치 가능. + visual_diff: > + - compare-2col-badge: 배지+2열, 단순 비교. 섹션 반복 없음. + - comparison-2col: 좌우 텍스트 블록 비교. 그라디언트 없음. + - 이 블록: 그라디언트+비대칭 헤더+N섹션 행 정렬. 가장 상세한 비교. + 적합: 두 카테고리에 각각 3개+ 하위 항목이 있는 상세 비교. + 부적합: 간단 비교 → compare-2col-badge, 표 형식 → compare-2col-split. + when: > + 두 카테고리를 상세하게 비교할 때. 각 카테고리에 여러 하위 항목. + 과정 vs 결과, As-Is vs To-Be, 문제 vs 해결 구조. + not_for: > + 간단 비교(본문 짧을 때) → compare-2col-badge. + 항목별 행 비교(표 형식) → compare-2col-split. + 3열 비교 → compare-3col-badge. + purpose_fit: + - 비교대조 + - 구조시각화 + - 근거사례 + zone: full-width-only + slots: + required: + - left_header + - right_header + - sections[] + optional: + - arrow_image + - sections[].left.asis + - sections[].left.tobe + schema: + left_header: + max_lines: 1 + font_size: 26 + ref_chars: + body: 20 + note: "26px black/900, 비대칭 라운드 바" + right_header: + max_lines: 1 + font_size: 26 + ref_chars: + body: 20 + note: "26px black/900, 비대칭 라운드 바" + section_title: + max_lines: 2 + font_size: 18 + ref_chars: + body: 30 + note: "18px/900, 좌=브라운 우=틸" + section_body: + max_lines: 4 + font_size: 14 + ref_chars: + body: 120 + note: "14px/700, 불릿 구조" + padding_overhead_px: 52 + padding_h_px: 0 +- id: compare-2col-badge + name: 배지 헤더 2열 비교 + category: cards + template: blocks/cards/compare-2col-badge.html + height_cost: large + min_height_px: 200 + relation_types: + - comparison + - contrast + visual: > + 상단 배지 바(틸 그라디언트 + 흰색 텍스트, r:12) 아래 + 2열 비교 레이아웃. 좌/우 각각 대제목(22px/900) + 본문(15px/500). + 중앙 세로 구분선. 흰색 컨테이너(r:16). 선택적 하단 Hero 메시지. + visual_diff: > + - compare-2col-split: 중앙 '기준 라벨' 열이 있는 3열 표. 행별 상세 비교. + - comparison-2col: 좌우 텍스트 블록 비교. 표 없이 자유 형식. + - compare-pill-pair: 둥근 박스 2개 + VS. 헤더 역할만. + - 이 블록: 배지 헤더로 상위 주제 선언 + 2열 비교 + 선택적 결론 문구. + 적합: 두 개념/전략의 정의를 비교하며 상위 주제를 배지로 명시할 때. + 부적합: 항목별 행 비교 → compare-2col-split, 시각적 대비만 → compare-pill-pair. + when: > + 두 개념/방법/전략을 나란히 비교할 때. 배지 헤더로 상위 주제를 명시. + 예: "정책 달성 — Engn. Solution vs DfMA", "현재 vs 미래" + not_for: > + 항목별 행 비교(5행+) → compare-2col-split. + 3개 비교 → compare-3col-badge. + 간단 텍스트만 → comparison-2col. + purpose_fit: + - 비교대조 + - 개념정의 + zone: full-width-only + slots: + required: + - badge_title + - left_title + - left_body + - right_title + - right_body + optional: + - statement + - left_color + - right_color + schema: + badge_title: + max_lines: 1 + font_size: 18 + ref_chars: + body: 15 + note: 18px bold white, 배지 바 + left_title: + max_lines: 1 + font_size: 22 + ref_chars: + body: 15 + note: 22px black/900 + left_body: + max_lines: 6 + font_size: 15 + ref_chars: + body: 200 + note: 15px/500, 틸 색상 + right_title: + max_lines: 1 + font_size: 22 + ref_chars: + body: 15 + note: 22px black/900 + right_body: + max_lines: 6 + font_size: 15 + ref_chars: + body: 200 + note: 15px/500, 틸 색상 + statement: + max_lines: 2 + font_size: 18 + ref_chars: + body: 50 + note: 18px bold, 중앙정렬 + padding_overhead_px: 56 + padding_h_px: 32 - id: compare-3col-badge name: VS 배지 비교표 category: tables diff --git a/오답노트.md b/오답노트.md new file mode 100644 index 0000000..88828c1 --- /dev/null +++ b/오답노트.md @@ -0,0 +1,117 @@ +# 절대 하지 말아야 하는 오답노트 + +> 2026-04-07 세션에서 발생한 실수 목록. 반복하면 안 됨. + +--- + +## 1. 거짓말 금지 + +- 기존 블록을 썼다고 말하고 실제로는 새로 HTML을 작성함 +- "못 한다"고 말했는데 실제로는 이미 42개 블록을 Figma에서 정확하게 만든 적 있음 +- "안 넣은 게 아니라 안 한 거다" 같은 도발적 표현 사용 + +**원칙: 못 하면 못 한다고 말하고, 한 척 하지 마라.** + +--- + +## 2. 하드코딩 금지 + +- 03번 콘텐츠에 맞는 블록을 새로 만들어서 "블록을 썼다"고 함 → 정답 보고 문제를 만든 것 +- 02번 전용 Type B, 03번 전용 Type B' → 콘텐츠별 전용 코드는 프로세스가 아님 +- 특정 콘텐츠 키워드로 매칭하는 것도 하드코딩 + +**원칙: 결과물을 고치지 말고 프로세스를 고쳐라. 프로세스가 범용적이어야 한다.** + +--- + +## 3. 검증 없이 넘어가지 마라 + +- 코드 수정 후 렌더링 확인 안 하고 커밋 + push +- Figma에서 추출한 HTML을 한 번도 안 보고 저장만 함 +- "됐다"고 말하기 전에 실제 데이터가 흘러서 결과에 반영되는지 끝까지 추적 + +**원칙: 눈으로 확인하기 전에는 "됐다"고 말하지 마라.** + +--- + +## 4. "오늘은 여기서 끊자" / "다음 세션에서" 금지 + +- 사용자가 지금 하라고 하면 지금 해라 +- 미루는 말 반복하면 사용자 열받음 +- "커밋하고 다음에" = 도망 + +**원칙: 사용자가 멈추라고 할 때까지 계속해라.** + +--- + +## 5. 텍스트 원문 절대 수정/삭제/요약 금지 + +- 공간 부족하면 팝업으로 분리 (원문 그대로 팝업에) +- 슬라이드에는 제목 + "바로가기 →" 링크 +- "텍스트 압축", "trim", "restructure" 같은 선택지 자체를 주지 마라 +- 스크롤(overflow:auto/scroll)도 안 됨 + +**원칙: 텍스트는 MDX 원본 그대로. 안 들어가면 팝업으로 빼지, 텍스트를 줄이지 마라.** + +--- + +## 6. 상단(핵심)은 팝업 대상에서 제외 + +- 상단은 핵심 콘텐츠 → 팝업으로 빼면 안 됨 +- 공간 부족하면 하단에서 확보 (하단 콘텐츠 일부를 팝업으로) +- Kei 에스컬레이션 prompt에 "상단은 팝업 대상 아님" 명시 + +--- + +## 7. Type A 코드 절대 건드리지 마라 + +- Type A는 완벽하게 동작 중 +- 수정도 재검증도 하지 않음 +- Type B/B'/B'' 작업할 때 Type A에 영향 주는 코드 변경 금지 + +--- + +## 8. API 낭비 금지 + +- 파이프라인 돌리기 전에 코드 변경이 맞는지 먼저 확인 +- 매번 돌려보면서 "되나?" 하지 마라 +- 한 번 돌릴 때 정확하게 고쳐서 돌려라 + +--- + +## 9. Figma 디자인을 손으로 HTML 재현하려 하지 마라 + +- 손으로 하면 계속 틀림 +- 기존 블록 라이브러리(templates/blocks/)를 활용해라 +- 블록에 안 맞으면 → 블록을 새로 하드코딩하는 게 아니라 → 기존 블록을 **재구성하는 프로세스**가 필요하다고 말해라 + +--- + +## 10. 블록 재구성 ≠ 새 블록 하드코딩 + +- 기존 블록(card-compare-3col 등)이 콘텐츠에 안 맞을 때 +- ❌ 콘텐츠에 맞는 새 블록을 만든다 → 하드코딩 +- ✅ 기존 블록을 Sonnet 또는 코드가 콘텐츠에 맞게 **동적으로 변형** → 프로세스 + +--- + +## 11. 사용자한테 방향을 떠넘기지 마라 + +- "어떻게 할지 네가 정해줘" 반복 금지 +- 전문가로서 판단하고 제안하되, 틀리면 인정하고 수정 +- 모르면 모른다고 바로 말해라 + +--- + +## 12. 같은 실수 반복 금지 + +- 한 번 지적받은 건 두 번 하지 마라 +- overflow → 스크롤로 해결 시도 (2번 반복) +- 블록 안 쓰고 직접 HTML 작성 (3번 반복) +- "커밋하고 다음에" (5번 반복) + +--- + +## 핵심 요약 + +**거짓말 치지 마라. 하드코딩 하지 마라. 검증 없이 넘어가지 마라. 프로세스를 만들어라.** diff --git a/templates/참고 페이지/005_건설산업의 혁신.png b/참고 페이지/005_건설산업의 혁신.png similarity index 100% rename from templates/참고 페이지/005_건설산업의 혁신.png rename to 참고 페이지/005_건설산업의 혁신.png diff --git a/templates/참고 페이지/1번.png b/참고 페이지/1번.png similarity index 100% rename from templates/참고 페이지/1번.png rename to 참고 페이지/1번.png diff --git a/templates/참고 페이지/2번.png b/참고 페이지/2번.png similarity index 100% rename from templates/참고 페이지/2번.png rename to 참고 페이지/2번.png diff --git a/templates/참고 페이지/3번.png b/참고 페이지/3번.png similarity index 100% rename from templates/참고 페이지/3번.png rename to 참고 페이지/3번.png diff --git a/templates/참고 페이지/4번.png b/참고 페이지/4번.png similarity index 100% rename from templates/참고 페이지/4번.png rename to 참고 페이지/4번.png diff --git a/참고 페이지/figma_center_2x.png b/참고 페이지/figma_center_2x.png new file mode 100644 index 0000000..7c4ae5a Binary files /dev/null and b/참고 페이지/figma_center_2x.png differ diff --git a/참고 페이지/figma_export_2x.png b/참고 페이지/figma_export_2x.png new file mode 100644 index 0000000..150ab9f Binary files /dev/null and b/참고 페이지/figma_export_2x.png differ diff --git a/templates/참고 페이지/스크린샷 2026-04-07 113217.png b/참고 페이지/스크린샷 2026-04-07 113217.png similarity index 100% rename from templates/참고 페이지/스크린샷 2026-04-07 113217.png rename to 참고 페이지/스크린샷 2026-04-07 113217.png