` 절대 배치 | 선택 가능, 접근성 |
| 실사 이미지 | `
![]()
` PNG | 재현 불가 |
| 회전된 도형 | 래퍼 div + `transform: rotate()` ([INSIGHT-GRADIENT.md](INSIGHT-GRADIENT.md)) | gradient 동시 회전 |
### 7-C. 보정 규칙
[RULES.md](RULES.md) R1~R16 모두 적용:
- R1: descender padding-bottom
- R2~R3: 회전/세로 텍스트
- R4: 그라데이션 텍스트
- R5: 다중 fills
- R6: 중복 노드
- R7: 흰 배경
- R8: 스케일 팩터
- R9: 순수 CSS 우선
- R10: blend mode 호환
- R11: stroke 정렬 (inside/outside)
- R12: viewBox padding
---
## STEP 8 — Selenium 렌더링 + 사람 눈 검증
```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from PIL import Image
import os, time
# _renders/ 폴더 없으면 생성
os.makedirs('block-tests/_renders', exist_ok=True)
opts = Options()
opts.add_argument('--headless=new')
opts.add_argument('--hide-scrollbars')
opts.add_argument('--force-device-scale-factor=1')
opts.add_argument('--window-size=1600,900')
d = webdriver.Chrome(options=opts)
p = os.path.abspath('block-tests/{slug}.html').replace('\\','/')
d.get('file:///' + p)
time.sleep(1.5)
d.save_screenshot('block-tests/_renders/{slug}_full.png')
r = d.execute_script(
'const r=document.querySelector(".slide").getBoundingClientRect();'
'return [r.x,r.y,r.width,r.height];'
)
Image.open('block-tests/_renders/{slug}_full.png').crop(
(int(r[0]), int(r[1]), int(r[0]+r[2]), int(r[1]+r[3]))
).save('block-tests/_renders/{slug}.png')
d.quit()
```
**검증 방식:**
- 자동 픽셀 diff는 하지 않음 (font 렌더 차이로 노이즈만 많음)
- Figma `get_screenshot` 응답과 Selenium 결과를 **사람 눈**으로 비교
- 차이 발견 시 STEP 5~7로 돌아가서 원인 파악 (값 수정 금지)
---
## STEP 9 — 결과물 저장
```
block-tests/
├── {slug}.html ← 변환물
├── {slug}_flat.md ← 플래튼/이상/변형 축 메모
└── _renders/
└── {slug}.png ← 검증 스크린샷
```
`{slug}` 명명 규칙: 의미 기반 kebab-case (예: `bim-goals-3circles`, `cards-3col-icon`).
프레임 ID는 metadata로 추적 가능하므로 파일명에 넣지 않음.
---
## STEP 10 — blocks_index.md 1줄 업데이트
`blocks_index.md` 끝에 한 줄 추가:
```markdown
| {slug} | {프레임 ID} | {1줄 변형 축 요약} | {날짜} |
```
이 인덱스가 패턴 발견의 단서가 된다. 다음 변환 시작 전에 이 인덱스를 한 번 훑어서 "이미 비슷한 거 했나?" 확인.
---
## 패턴 → 템플릿화 (1번째부터 즉시)
**규칙: 1번째 등장부터 templates_staging 작성. 정적 HTML만 두는 것 금지.**
| 등장 횟수 | 처리 |
|---------|------|
| **1번째** | `block-tests/{slug}.html` (1:1 reference) + `templates_staging/{pattern_id}.html.j2` (Jinja2 + meta.yaml + example.yaml) **함께 작성** |
| 2번째 | 기존 staging 템플릿이 새 데이터로 잘 렌더되는지 확인. 안 되면 템플릿 수정. example 추가. |
| 3번째 이후 | 동일 |
**왜 1번째부터 템플릿화하나?**
- 변환의 목적은 **블록 라이브러리 구축**, 단순 HTML 복제가 아님
- 1:1 단계에서 발견한 인사이트(R13 등)를 즉시 템플릿에 반영해야 잊지 않음
- 사용자가 검수할 때 "이게 블록으로 어떻게 작동할지" 즉시 확인 가능
- 2번째 등장을 기다리면 사용자 수동 복제 작업이 누적됨 (work-creating-work)
**Stage 2 산출물:**
```
templates_staging/
├── {pattern_id}.html.j2 ← Jinja2 템플릿 본체
└── {pattern_id}.meta.yaml ← when / slots / min_size_px / 변형 축 초안
```
여기까지가 **에이전트 책임의 끝.**
---
## 🚧 프로모션 게이트 (사용자 전용)
> 이 게이트 이후 작업은 **에이전트가 절대 수행하지 않는다.** 모든 design_agent/templates/ 변경은 사용자 본인이 직접 한다.
### 사용자가 수행할 작업
1. **검수**: `templates_staging/{pattern_id}.html.j2` 를 다양한 파라미터로 렌더 테스트
2. **품질 게이트 통과 확인**:
- [ ] 1:1 변환물과 시각적으로 동일한가
- [ ] 슬롯 파라미터를 바꿔도 깨지지 않는가 (원 4개, 라벨 0개 등 극단 케이스)
- [ ] meta.yaml의 when/slots가 design_agent의 다른 블록과 충돌 없는가
3. **이동**: `templates_staging/{pattern_id}.html.j2` → `design_agent/templates/blocks/{category}/`
4. **등록**: `design_agent/templates/catalog.yaml` 에 when/slots/min_size_px 추가
5. **상태 업데이트**: `blocks_index.md` 의 해당 행 상태 → `promoted`
### 에이전트의 역할
- staging 작성까지만
- 사용자 요청 없이 `design_agent/templates/` 를 절대 읽거나 쓰지 않음
- "templates/ 에 옮겨드릴까요?" 같은 제안 금지 (월권)
- 사용자가 명시적으로 "이 staging 결과 검토해줘"라고 요청하면 → staging 폴더 내에서만 검토
---
## 안티 패턴 (하지 말 것)
| ❌ 하지 말 것 | 이유 |
|------------|-----|
| 사전에 인벤토리/지문/군집 단계 | work-creating-work, 패턴은 변환하면서 발견됨 |
| 1번째 등장은 정적 HTML로만 두기 (templates_staging 미작성) | work-creating-work, 인사이트 잊혀짐. 1번째부터 템플릿 작성 |
| 컨텍스트 차면 강제 새 세션 | compact 사용. 핵심 결정은 모두 파일에 박혀있어 손실 없음 |
| Figma 데이터 안 보고 멀티모달 이미지로 추측 | 미묘한 alpha/blend에서 틀림 |
| "여기 1px 어색하니 다른 곳도 같이 바꾸자" | 사용자 피드백만 정확히 반영 |
| 같은 자산을 매번 새로 다운로드 | `block-tests/assets/shared/` 캐시 활용 |
| 그라데이션 각도/색을 눈대중으로 | gradient_math.py로 수학 도출 |
| gradient_math.py 함수 코드 인라인 복사 | import만 한다. 복사하면 수식 어긋남 |
| 세션 시작에 blocks_index.md 안 읽음 | 패턴 발견 트리거 영영 작동 안 함 |
| `design_agent/templates/` 직접 수정 | 프로모션은 사용자 전용. 에이전트는 staging까지만 |
| "templates/ 옮겨드릴까요?" 제안 | 월권. 사용자가 알아서 함 |
| `prerequisites-3col.html` 을 신규 변환 레퍼런스로 사용 | 구 방법론 (R8/R9 미적용). legacy 표시됨 |