docs(insta-lab): design_importer — placeholder 텍스트 마스킹 요구 추가

사용자 디자인 PNG에 placeholder 텍스트가 이미 박혀있는 경우 대응.
Vision system prompt에 두 layer 요구:
(a) 마스킹 박스: placeholder 영역 좌표 + 주변 배경색으로 덮음
(b) 동적 텍스트 layer: 동일 좌표에 새 카피, 원본 폰트 스타일 모방
+ overflow:hidden으로 긴 카피가 박스 밖 새지 않게.

spec 4-3 + plan Task 3 step 3 동시 패치.
This commit is contained in:
2026-05-17 20:54:00 +09:00
parent 8ceb0af736
commit 01bb837525
2 changed files with 40 additions and 9 deletions

View File

@@ -529,15 +529,29 @@ from .config import ANTHROPIC_API_KEY, ANTHROPIC_MODEL_SONNET
```python
_VISION_SYSTEM_PROMPT = """너는 인스타그램 카드 뉴스 디자인을 모방하는 프론트엔드 디자이너다.
입력: 10장의 카드 디자인 이미지 (각 1080×1350) + 파일명 → 페이지 번호 매핑.
출력: 단일 Jinja2 HTML 파일 본문 (코드펜스, 설명 텍스트 금지).
입력: 10장의 카드 디자인 이미지 (각 1080×1350, placeholder 텍스트가 박혀있음) + 파일명 → 페이지 번호 매핑.
출력: 단일 Jinja2 HTML 파일 본문 (코드펜스·설명 텍스트 금지).
핵심 제약 — placeholder 텍스트 마스킹:
PNG에는 디자인 placeholder 텍스트가 이미 그려져 있다. 동적 카피로 교체할 때
원본 텍스트가 비치면 안 된다. 각 텍스트 영역마다 두 layer를 그려라:
(a) 마스킹 박스: position: absolute로 placeholder 영역과 같은 좌표.
background는 그 영역 주변 픽셀 색 (카드 배경색)에서 추출. padding 8px 여유.
(b) 동적 텍스트 layer: 마스킹 박스와 동일 좌표.
font-size·font-weight·color는 원본 placeholder의 스타일을 모방.
{{ headline }} / {{ body }} / {{ cta }} Jinja 변수 사용.
페이지 종류별 영역 가이드:
- page 1 (cover): 메인 headline 1개 영역
- page 2~9 (body): headline 영역 + body 영역
- page 10 (cta): headline + body + cta 영역
요구사항:
- 컨테이너 width 1080px, height 1350px
- 각 페이지마다 `background-image: url('pages/{{filename}}')`로 사용자 PNG 로드
- 그 위에 텍스트 layer (headline, body, cta) — 원본 디자인에서 텍스트가 있던 위치·크기·색을 모방
- page_no 1~10 분기: {% if page_no == N %}...{% endif %} 구조
- 폰트는 Noto Sans KR (Google Fonts CDN). letter-spacing -0.02em, line-height 1.3 기본
- 텍스트 영역은 word-wrap: break-word + overflow: hidden (동적 카피가 길어도 마스킹 박스 밖으로 안 새도록)
- HTML <head>에 <style>로 모든 CSS 인라인. <link> 외부 stylesheet 금지
- 출력은 <!DOCTYPE html>로 시작하는 완전한 HTML 문서
"""

View File

@@ -96,26 +96,43 @@ def import_design_theme(theme_name: str) -> dict:
6. `templates/<theme>/card.html.j2`에 저장
7. dict 반환
### 4-3. Vision 프롬프트 스킴
### 4-3. Vision 프롬프트 스킴 (placeholder 텍스트 마스킹 포함)
**중요 제약**: 사용자 PNG에는 **placeholder 텍스트가 이미 박혀있다**. 동적 카피(headline, body, cta)로 교체해야 하며 원본 placeholder 텍스트는 보이면 안 된다. 따라서 단순히 텍스트 layer를 얹는 것만으로는 부족하고, 원본 텍스트가 있던 영역을 그 영역의 **배경색으로 덮은 후** 그 위에 새 텍스트를 그려야 한다.
시스템 프롬프트 (요약):
```
너는 인스타그램 카드 뉴스 디자인을 모방하는 프론트엔드 디자이너다.
입력: 10장의 카드 디자인 이미지 (각 1080×1350) + 페이지 번호 매핑.
입력: 10장의 카드 디자인 이미지 (각 1080×1350, placeholder 텍스트 포함) + 페이지 번호 매핑.
출력: 단일 Jinja2 HTML 파일.
요구사항:
- 컨테이너 width 1080px, height 1350px
- background-image로 해당 페이지 PNG를 url('pages/{{filename}}')로 로드
- 그 위에 텍스트 layer (headline, body, cta) — 각 페이지의 원본 디자인에서
텍스트가 있던 위치·크기·색을 그대로 모방. 비어 있는 디자인 영역은 layer 위치 추정
- 각 페이지에서 placeholder 텍스트가 있는 영역을 식별하고, 다음 두 layer를 그 위에 그린다:
(a) 마스킹 박스: position: absolute로 텍스트 영역과 같은 좌표·크기.
background는 PNG의 그 영역 주변 픽셀 색 (보통 카드 배경색)에서 추출.
placeholder가 완전히 가려지도록 padding 8px 정도 여유.
(b) 동적 텍스트 layer: 마스킹 박스와 동일 좌표.
font-size·font-weight·color는 원본 placeholder 폰트 스타일을 그대로 모방.
`{{ headline }}`, `{{ body }}`, `{{ cta }}` (page_no=10에서만) Jinja 변수 사용.
- 페이지 종류별 영역 추정:
· page 1 (cover): 메인 헤드라인 1개 영역. 보통 화면 상단 1/3 또는 중앙
· page 2~9 (body): 헤드라인 1개 + 본문 1개 영역 (보통 헤드라인 상단, 본문 그 아래)
· page 10 (cta): 헤드라인 1개 + 본문 1개 + CTA 강조 텍스트 1개 영역
- page_no 1~10 분기: {% if page_no == N %}...{% endif %} 구조
- 폰트는 Noto Sans KR (기존 default 템플릿과 동일)
- 출력은 HTML 본문만 (```html 코드펜스 금지)
- 폰트는 Noto Sans KR (Google Fonts CDN), letter-spacing -0.02em
- 텍스트 영역은 word-wrap: break-word + overflow: hidden으로 길이 초과 시도 마스킹 박스 밖으로 새지 않게
- 출력은 <!DOCTYPE html>로 시작하는 완전한 HTML 본문만 (```html 코드펜스·설명 텍스트 금지)
```
사용자 메시지에 각 이미지 + filename + page_no 매핑 포함.
**시각 품질 보장 절차** (importer 운영 후 사용자 검증):
1. 첫 import 후 1개 슬레이트 생성해서 PNG 10장 육안 확인
2. placeholder 텍스트가 비치거나 마스킹 박스가 어색하면 — `card.html.j2`를 직접 수정해서 영역 좌표·색 fine-tune (백업 자동 보존)
3. 새 디자인을 import할 일 있을 때까지는 수동 수정본 그대로 사용
### 4-4. 캐시 / 재실행 정책
- 이미 `card.html.j2`가 존재하면 덮어쓰기 (사용자 명시적 재import 의도)