전체 401 files (397 추가 + 4 수정), 14304 insertions.
추가:
- figma_to_html_agent/blocks/ — Figma 변환 결과 (32 frame, ~79MB).
각 frame folder = {analysis.md, flat.md, texts.md, index.html, assets/,
_renders/, _render.py, RELATIONSHIPS.md / STATUS.md / classification.md
(일부 frame)}.
Phase Z 의 *figma source layer* — runtime 에서 직접 사용 X, contract /
partial / builder adapter (미래 axis A) 의 source.
- figma_to_html_agent/DISCUSSION-SUMMARY-20260411.md — 변환 설계 회의 기록.
- figma_to_html_agent/HARNESS.md — 변환 검증 harness.
- figma_to_html_agent/scripts/fetch_figma_screenshots.py — Figma 스크린샷 자동 수집.
수정:
- figma_to_html_agent/PROCESS-CONTROL.md / PROCESS.md / RULES.md —
변환 프로세스 / 룰 갱신 (R8/R9 lock 강화 등).
- figma_to_html_agent/blocks_index.md — 32 frame 인덱스 갱신.
Phase Z 영향 0 (figma_to_html_agent/blocks/ 가 V4 catalog +
templates/phase_z2/families adapter 의 source — runtime 에서 직접 import X).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
295 lines
11 KiB
Markdown
295 lines
11 KiB
Markdown
# 변환 하네스 (Conversion Harness)
|
||
|
||
> **이 체크리스트의 모든 항목을 순서대로 통과해야 한다. 건너뛰기 금지.**
|
||
> 각 항목에서 "확인"이 안 되면 다음으로 넘어가지 않는다.
|
||
> **2층 구조: 1층(행동 통제) → 2층(구현)**. 1층을 통과하지 않으면 2층 진입 금지.
|
||
|
||
---
|
||
|
||
# ═══ 1층: 행동 통제 하네스 ═══
|
||
|
||
## A. 사용자 요청 해석
|
||
|
||
- [ ] 사용자가 실제로 말한 문제를 **한 문장으로** 다시 적었는가?
|
||
- [ ] 내가 하려는 수정이 **그 문제에 직접 대응**하는가?
|
||
- [ ] 사용자가 말하지 않은 구조 변경을 하려면 **사전 합의**가 필요한가?
|
||
- [ ] "이것도 같이 바꾸면 좋겠다"는 생각이 들면 → **멈추고 물어본다**
|
||
|
||
## B. 블록 분류 (patch / rewrite / hold)
|
||
|
||
작업 시작 전 반드시 분류하고 근거를 3줄로 적는다.
|
||
|
||
```
|
||
이 블록은 무엇인가?
|
||
├── patch — 구조는 살아 있고 특정 부분만 수정하면 됨
|
||
│ 근거: ___
|
||
├── rewrite — 구조 자체가 틀어져서 처음부터 다시 해야 함
|
||
│ 근거: ___
|
||
└── hold — 지금 건드리지 않고 보류
|
||
근거: ___
|
||
```
|
||
|
||
- [ ] 분류 결정함 → `blocks/{id}/classification.md`에 기록
|
||
- [ ] 근거 3줄 적음
|
||
- [ ] **patch가 아닌 블록에 임의 구조 전환 금지**
|
||
- [ ] **rewrite 블록은 사용자 확인 후에만 착수**
|
||
|
||
## C. 변경 범위 제한
|
||
|
||
- [ ] **이번 수정의 단일 목표**를 한 문장으로 적었는가?
|
||
- [ ] 이번 수정에서 바꾸는 축은 **1개**인가?
|
||
- 예: spacing만 / bullet model만 / gradient CSS 변환만
|
||
- [ ] 다른 축은 건드리지 않았는가?
|
||
- [ ] 현재 정상 동작하는 요소를 **변경 금지 목록**으로 적었는가?
|
||
|
||
```
|
||
변경 대상: ___
|
||
변경하지 않는 것: ___
|
||
```
|
||
|
||
## D. 변경 전 기록
|
||
|
||
- [ ] 수정 전 현재 값/구조 기록 (되돌릴 수 있도록)
|
||
- [ ] 변경 전 렌더링 스크린샷 baseline 저장
|
||
|
||
## E. 중단 조건
|
||
|
||
아래 상황 발생 시 **즉시 멈추고 사용자에게 보고**:
|
||
|
||
- [ ] 인코딩 깨짐 발견
|
||
- [ ] MCP 좌표와 렌더 결과가 크게 다름 (30px+ 이상 차이)
|
||
- [ ] 패치하려던 블록이 구조 붕괴 상태
|
||
- [ ] 한 군데 고치니 다른 곳이 깨짐 (cascade failure)
|
||
- [ ] 사용자 요청과 다른 방향으로 가고 있음을 인지
|
||
|
||
→ patch 중단
|
||
→ rewrite required로 분류 전환
|
||
→ `blocks/{id}/STATUS.md` 남기고 다음 블록으로
|
||
|
||
## F. 완료 판정
|
||
|
||
patch 또는 rewrite가 끝났다고 판단하기 전에:
|
||
|
||
- [ ] 사용자가 지적한 문제가 **실제로 사라졌는가** (렌더링 확인)
|
||
- [ ] 새로 생긴 **부작용이 없는가**
|
||
- [ ] baseline 대비 **더 나빠진 요소가 없는가**
|
||
- [ ] 아래 4개 산출물을 남겼는가:
|
||
- before screenshot
|
||
- after screenshot
|
||
- 변경 요약 3줄
|
||
- classification 결과 (patch/rewrite/hold)
|
||
|
||
위 전부 통과해야 "완료". 하나라도 안 되면 미완료.
|
||
|
||
---
|
||
|
||
# ═══ 2층: 구현 하네스 ═══
|
||
|
||
> **1층 A~F를 모두 통과한 후에만 아래 진행**
|
||
|
||
## 0. 시작 전 — 규칙 파일 읽기 + 행동 원칙 확인
|
||
|
||
- [ ] RULES.md 읽음 (R1~R19 전부)
|
||
- [ ] PROCESS-CONTROL.md 읽음 (규칙 1~8)
|
||
- [ ] PROCESS.md 읽음 (STEP 0~10)
|
||
- [ ] HARNESS.md 읽음 (이 파일)
|
||
- [ ] blocks_index.md 읽음 (기존 패턴 확인)
|
||
|
||
### 행동 원칙 (PROCESS-CONTROL에서, 매 작업 전 상기)
|
||
- [ ] **소스는 Figma 데이터다** — PNG를 보고 판단하지 않음 (규칙1)
|
||
- [ ] **이미지 해석 금지** — 멀티모달로 gradient 방향 추측 안 함 (규칙2)
|
||
- [ ] **작동하는 것은 건드리지 않는다** — A만 문제면 A만 수정 (규칙3)
|
||
- [ ] **한 번에 하나만 바꾼다** — gradient 각도와 border-radius 동시 변경 금지 (규칙4)
|
||
- [ ] **사용자가 말한 것만 한다** — 자의적 해석 금지 (규칙5)
|
||
- [ ] **찍어맞추기 금지** — 값을 바꾸기 전에 WHY를 먼저 설명 (규칙6)
|
||
- [ ] **쉬운 전면 재작성 금지** — 80점에서 2개 고칠 때 구조를 갈아엎지 않음 (규칙7)
|
||
- [ ] **MCP 데이터 전수 반영** — "핵심만", "단순화" 금지 (규칙8)
|
||
|
||
---
|
||
|
||
## 1. MCP 데이터 수집
|
||
|
||
- [ ] get_metadata 호출 → 모든 노드 ID, 위치, 크기 확보
|
||
- [ ] get_design_context 호출 → gradient, font, style, rotation 확보
|
||
- [ ] 에셋 URL 목록 추출
|
||
|
||
---
|
||
|
||
## 2. 에셋 분류 — R9 CSS vs 이미지 판정 (에셋마다 반드시 수행)
|
||
|
||
각 에셋에 대해:
|
||
|
||
```
|
||
이 에셋이 뭔가?
|
||
├── 단순 사각형 + gradient → CSS linear-gradient + border-radius [R9]
|
||
├── 단순 원 + gradient → CSS border-radius:50% + linear-gradient [R9]
|
||
├── 단순 직선/점선 → CSS border [R9]
|
||
├── 단색 사각형 → CSS background-color [R9]
|
||
├── plus-darker blend → multiply로 교체 [R10]
|
||
└── 복잡 path / 사진 / 아이콘 / 곡선 → 이미지 유지
|
||
```
|
||
|
||
- [ ] 모든 에셋 분류 완료
|
||
- [ ] CSS 대체 가능한 에셋은 다운로드하지 않음
|
||
- [ ] 이미지 유지 에셋만 다운로드
|
||
|
||
---
|
||
|
||
## 3. gradient 변환 — R9 CSS 대체 에셋
|
||
|
||
CSS로 대체하기로 한 에셋마다:
|
||
|
||
- [ ] SVG 파일을 열어 linearGradient 데이터 추출
|
||
- [ ] gradient_math.py로 CSS linear-gradient 변환 (인라인 복사 금지)
|
||
- [ ] viewBox padding이 있으면 R12 remap 적용
|
||
- [ ] 변환 결과 기록
|
||
|
||
---
|
||
|
||
## 4. 구조 결정 — R17 레이아웃 타입
|
||
|
||
```
|
||
이 블록의 레이아웃은?
|
||
├── 순차 행 (비교표, 이슈 목록, 불릿 리스트)
|
||
│ → flex column (행 간) + flex row (행 내부) [R17]
|
||
│ → 텍스트 늘면 행이 밀림
|
||
│
|
||
├── 표 (행×열 구조)
|
||
│ → CSS grid [R17]
|
||
│ → border가 곧 그리드 라인
|
||
│ → 셀 높이 auto
|
||
│
|
||
├── 2D 다이어그램 (원, 노드, 겹침)
|
||
│ → absolute + 명시 height + zoom [R19]
|
||
│ → 겹침이 있으므로 flex 불가
|
||
│
|
||
└── 좌우 분할 (좌:이미지 / 우:목록)
|
||
→ display:flex (좌:flex-none / 우:flex column)
|
||
```
|
||
|
||
- [ ] 레이아웃 타입 결정
|
||
- [ ] zoom 적용 (transform:scale 금지) [R19]
|
||
|
||
---
|
||
|
||
## 5. HTML 작성 — 요소별 체크
|
||
|
||
### 5-A. DOM 순서
|
||
- [ ] MCP metadata 순서 = HTML DOM 순서 (나중 요소가 위에 렌더)
|
||
- [ ] z-index 별도 지정 필요 없음 (DOM 순서로 해결)
|
||
|
||
### 5-B. 텍스트 요소
|
||
- [ ] 본문 텍스트에 position:absolute 사용 안 함 [R17]
|
||
- [ ] overflow:hidden으로 텍스트 숨기기 안 함 [R17]
|
||
- [ ] 고정 height로 텍스트 제한 안 함 [R17]
|
||
- [ ] word-break: keep-all 적용 [R14]
|
||
- [ ] descender 보정 필요한가? [R1]
|
||
- line-height / font-size < 1.448 (Noto Sans KR) → padding-bottom 계산
|
||
- [ ] gradient 텍스트인가? → background-clip: text [R4]
|
||
- [ ] 다중 fills인가? → 첫 번째 불투명 fill만 사용 [R5]
|
||
- [ ] 중복 노드인가? (동일 좌표 + 동일 내용) → 1개만 렌더 [R6]
|
||
- [ ] 세로 텍스트인가? (width < fontSize × 0.8) → `<br>` 줄바꿈, writing-mode 사용 금지 [R3]
|
||
- [ ] vertical center 정렬이 필요한가? → flex justify-center [R15]
|
||
- [ ] 불필요한 `<br>` 삽입 안 함 (자연 wrap에 맡김)
|
||
|
||
### 5-C. 불릿/마커 리스트 [R13]
|
||
- [ ] `<ul><li>` 사용 안 함
|
||
- [ ] R13 flex pair 구조 사용:
|
||
```html
|
||
<div class="bullet-row">
|
||
<span class="marker">•</span>
|
||
<span class="text">내용</span>
|
||
</div>
|
||
```
|
||
- [ ] 2줄째가 첫째 줄 텍스트 시작점에 정렬되는가?
|
||
- [ ] level 2 (- dash)는 padding-left로 한 단계 더 들여쓰기
|
||
- [ ] 우측 배치: bullet-row 자체는 좌→우 읽기, 컨테이너가 우측 정렬
|
||
|
||
### 5-D. 회전 요소 [R2]
|
||
- [ ] MCP bbox가 회전된 상태인가? (width > height × 1.5 for 단일 문자)
|
||
- [ ] 회전 bbox의 x좌표를 그대로 left에 넣지 않음 [R2 addendum]
|
||
- [ ] 같은 축 요소들의 center_x를 기준으로 정렬
|
||
- [ ] design_context의 center 좌표 + translate(-50%,-50%) 사용
|
||
|
||
### 5-E. 이미지 프레임 [R16]
|
||
- [ ] overflow:hidden + left/width로 부분 표시
|
||
- [ ] rotate(180deg) 하단은 이미지 배치 반전
|
||
- [ ] crop variant와 label position 분리 [R18]
|
||
- [ ] pill 접합이 있는 경우: seam 메타데이터 기록 (pill_seam_meta.md)
|
||
- left_seam, right_seam, flat_start, flat_end 측정
|
||
- label anchor는 현재 designer-tuned fallback, 장기 computed
|
||
|
||
### 5-F. CSS gradient/도형 [R9]
|
||
- [ ] 단순 도형은 CSS div + border-radius + linear-gradient
|
||
- [ ] gradient_math.py 결과값 사용 (감으로 넣지 않음)
|
||
- [ ] stroke: border로 변환 [R11 케이스A/B]
|
||
|
||
### 5-G. 배경/장식
|
||
- [ ] .slide 배경은 항상 #fff [R7]
|
||
- [ ] 장식 요소(배경 텍스처, 아크 등)는 absolute OK
|
||
- [ ] 장식 요소의 mix-blend-mode 반영 (multiply 등)
|
||
|
||
---
|
||
|
||
## 6. Flexible 구조 검증
|
||
|
||
- [ ] 텍스트를 2배로 늘렸을 때 겹치지 않는가?
|
||
- [ ] 텍스트를 절반으로 줄였을 때 빈 공간이 방치되지 않는가?
|
||
- [ ] 불릿 항목을 추가했을 때 아래 요소가 자연스럽게 밀리는가?
|
||
- [ ] 표의 경우: 셀 텍스트 늘면 행이 늘고 border가 따라가는가?
|
||
|
||
---
|
||
|
||
## 7. 산출물 작성
|
||
|
||
- [ ] texts.md — 콘텐츠 텍스트만 (TF-IDF용)
|
||
- 구조 메타(노드 ID, 블릿 개수, 역할 설명) 넣지 않음
|
||
- 섹션별 그룹핑은 가독성 위해 OK
|
||
- 한자/괄호/장식 문자 제외
|
||
- [ ] flat.md — 모든 노드 좌표/크기/속성, 변형 축, sub-pattern
|
||
- "간략하게" 금지 — 실측 기록부에 간략은 없다
|
||
- 이상 탐지 결과 포함 (회전, 세로 텍스트, 중복)
|
||
- [ ] index.html — 위 체크 모두 통과한 HTML
|
||
|
||
---
|
||
|
||
## 8. 검증
|
||
|
||
- [ ] Selenium 스크린샷
|
||
- [ ] Figma 원본과 시각 비교
|
||
- [ ] texts.md의 모든 텍스트가 index.html에 존재
|
||
- [ ] flat.md의 모든 시각 요소가 index.html에 반영
|
||
- [ ] CSS 대체한 에셋의 assets/ 폴더에서 삭제 확인
|
||
|
||
---
|
||
|
||
## 9. 완료 후
|
||
|
||
- [ ] blocks_index.md에 1줄 추가 (STEP 10)
|
||
- [ ] 기존 패턴과 비교 — 2번째 등장이면 templates_staging 진행 여부 확인
|
||
|
||
---
|
||
|
||
## 수정 시 추가 체크 (기존 블록 수정할 때)
|
||
|
||
- [ ] 수정 전 현재 값 기록 (변경 전)
|
||
- [ ] 수정 후 변경한 값 기록 (변경 후)
|
||
- [ ] 되돌려야 할 때 어디로 돌아가는지 알아야 한다 (PROCESS-CONTROL 규칙3)
|
||
- [ ] A만 문제면 A만 수정 — B, C를 "같은 이유로 틀릴 것 같다"고 함께 바꾸지 않음
|
||
- [ ] 구조 변경이 불가피하면 사전에 영향 범위 분석 + 사용자 확인 후 진행
|
||
|
||
---
|
||
|
||
## 절대 하지 말 것 (매번 확인)
|
||
|
||
- [ ] PNG/SVG를 CSS로 안 바꾸고 img src로 넣기 [R9 위반]
|
||
- **단순 gradient bar, rectangle, circle, line은 기본적으로 CSS다.**
|
||
- **이미지 유지가 필요하면 "왜 CSS 불가인지"를 먼저 적고 진행한다.**
|
||
- [ ] 본문 텍스트를 absolute로 배치 [R17 위반]
|
||
- [ ] overflow:hidden으로 텍스트 숨기기 [R17 위반]
|
||
- [ ] transform:scale 사용 (zoom 사용) [R19 위반]
|
||
- [ ] `<ul><li>` 불릿 사용 (flex pair 사용) [R13 위반]
|
||
- [ ] gradient 값을 감으로 넣기 (gradient_math.py 사용)
|
||
- [ ] MCP 회전 bbox x좌표를 그대로 left에 넣기 [R2 위반]
|
||
- [ ] 규칙 파일 안 읽고 작업 시작
|