# Clean 템플릿 가이드 ## 1. 소개 Clean은 밝은 회색 바탕과 선명한 강조색을 쓰는 범용 정보 전달 템플릿이다. 개발, API, 비즈니스, 교육처럼 구조가 중요한 주제에 적합하고, 사진 자체가 주인공인 여행 화보나 감성 포토 에세이에는 적합하지 않다. ## 2. 톤 가이드 단정적인 평서문을 쓴다. 한 슬라이드에는 한 가지 주장만 담고, 제목을 물음표로 끝내지 않는다. 전문 용어는 처음 등장할 때 짧게 풀어 쓰고 과장 표현은 피한다. ## 3. 슬라이드 흐름 권장 기본 흐름은 `cover → content-badge/content → content-stat/content-list/content-steps → cta`다. 비교는 `content-split`, 인용은 `content-quote`, 코드는 `content-code`, 숫자 중심 설명은 `content-bigdata`를 사용한다. `cover`와 `cta`는 각각 정확히 1장이다. ## 4. 슬롯별 작성 요령 아래 슬롯 한계는 등록 시 manifest에서 자동 생성했다. design_max는 디자인 권장 상한이며 초과해도 렌더는 성공하지만 `design_max_exceeded` 경고가 발생한다. max_chars는 실측 하드 상한이며 초과하면 422 `max_chars_exceeded`가 발생한다. 다만 max_chars는 레이아웃 안전을 보장하는 값이 아니라, 같은 글자 수라도 글자 폭이나 줄바꿈에 따라 max_chars 이내에서 렌더 영역을 넘을 수 있다. 이 경우 렌더는 성공하고 결과 이미지와 함께 `text_overflow` 등의 warning을 반환하므로, 경고가 발생한 슬롯의 문구를 더 줄여 다시 렌더한다. 이 수치는 손으로 쓴 것이 아니라 manifest가 원본이다 — 본 가이드와 manifest는 영구히 일치한다. - 요청 크기: `POST /v1/renders`의 전체 JSON 요청 본문 상한은 1,048,576바이트(1MB)다. 초과하면 HTTP 413 `payload_too_large`가 발생한다. - 글쓰기 원칙: 한 슬라이드에 한 주장. 좋은 예: `API 문서를 자동으로 검증하는 법`. 나쁜 예: `정말 놀랍고 엄청난 API 문서 자동화에 관하여 알아볼까요?`. - 브랜딩: `brand_logo_url`은 프로젝트 브랜드 자산(`logo_horizontal`)으로 렌더 시 자동 공급된다. 슬롯 값으로 데이터 URI를 직접 넣지 않는다. - 색상: `accent_color`는 manifest 테마 또는 `brand.colors.accent`의 `#RRGGBB`로 자동 공급된다. - 이미지: `image` 타입 슬롯은 공개 HTTPS URL과 `data:image/;base64,...` 데이터 URI를 모두 허용한다. 실사진은 본문 상한을 피하도록 원격 HTTPS URL을 사용하고, 데이터 URI는 로고·아이콘 같은 작은 자산에만 사용한다. 슬라이드 타입별로 아래 소절을 확인한다. 슬롯 이름·필수 여부·한계값은 manifest에서 생성되며, 타입별 작성 요령은 manifest의 `slide_types[].guidance`가 원본이다. ### `content-badge` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `badge_text` | 아니오 | max 330자 | | `headline` | 예 | max 15자 | | `body` | 예 | max 33자 | | `subtext` | 아니오 | max 646자 | ### `content-bigdata` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `headline` | 예 | max 26자 | | `bigdata_number` | 예 | max 16자 | | `bigdata_unit` | 아니오 | max 225자 | | `body` | 예 | max 31자 | | `subtext` | 아니오 | max 576자 | ### `content-code` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `headline` | 예 | max 26자 | | `filename` | 아니오 | max 1408자 | | `code` | 예 | max 464자 | | `body` | 예 | max 37자 | ### `content-fullimage` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `image_url` | 예 | 이미지(공개 HTTPS URL 또는 data URI) | | `badge_text` | 아니오 | max 774자 | | `body` | 예 | max 32자 | | `badge2_text` | 아니오 | max 1032자 | | `body2` | 아니오 | max 32자 | | `headline` | 예 | max 13자 | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | ### `content-grid` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `headline` | 예 | max 18자 | | `grid1_icon` | 예 | max 108자 | | `grid1_title` | 예 | max 32자 | | `grid1_desc` | 예 | max 27자 | | `grid2_icon` | 예 | max 108자 | | `grid2_title` | 예 | max 27자 | | `grid2_desc` | 예 | max 23자 | | `grid3_icon` | 예 | max 108자 | | `grid3_title` | 예 | max 32자 | | `grid3_desc` | 예 | max 27자 | | `grid4_icon` | 예 | max 108자 | | `grid4_title` | 예 | max 27자 | | `grid4_desc` | 예 | max 23자 | ### `content-highlight` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `headline` | 예 | max 26자 | | `emphasis` | 예 | max 16자 | | `body` | 예 | max 31자 | | `subtext` | 아니오 | max 578자 | ### `content-image` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `badge_number` | 아니오 | max 9자 | | `image_url` | 예 | 이미지(공개 HTTPS URL 또는 data URI) | | `headline` | 예 | max 22자 | | `body` | 예 | max 37자 | ### `content-list` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `headline` | 예 | max 17자 | | `item1` | 예 | max 32자 | | `item2` | 예 | max 32자 | | `item3` | 예 | max 32자 | | `item4` | 예 | max 32자 | | `item5` | 예 | max 32자 | ### `content-quote` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `body` | 예 | max 28자 | | `headline` | 예 | max 630자 | ### `content-split` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `headline` | 예 | max 18자 | | `left_title` | 예 | max 276자 | | `left_body` | 예 | max 38자 | | `right_title` | 예 | max 276자 | | `right_body` | 예 | max 32자 | ### `content-stat` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `headline` | 예 | max 25자 | | `emphasis` | 예 | max 42자 | | `body` | 예 | max 31자 | ### `content-steps` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `headline` | 예 | max 18자 | | `step1` | 예 | max 33자 | | `step2` | 예 | max 33자 | | `step3` | 예 | max 33자 | ### `content` (min 0, max 10) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | | `badge_number` | 아니오 | max 16자 | | `headline` | 예 | max 16자 | | `body` | 예 | max 35자 | ### `cover` (min 1, max 1) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `image_url` | 아니오 | 이미지(공개 HTTPS URL 또는 data URI) | | `subtext` | 아니오 | max 25자 | | `headline` | 예 | max 11자 | | `headline_label` | 아니오 | max 189자 | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | ### `cta` (min 1, max 1) | 슬롯 | 필수 | 형식·한계 | | --- | --- | --- | | `accent_color` | 아니오 | 색상(#RRGGBB, 자동 공급) | | `headline` | 예 | max 14자 | | `subtext` | 아니오 | max 33자 | | `cta_text` | 예 | max 31자 | | `tag1` | 아니오 | max 510자 | | `tag2` | 아니오 | max 476자 | | `tag3` | 아니오 | max 442자 | | `brand_logo_url` | 아니오 | 브랜드 자산(logo_horizontal) | ## 5. 완성된 slides.json 예시 다음 JSON은 그대로 렌더 요청 본문으로 사용할 수 있다. ```json { "template": "clean", "format": "instagram", "brand": { "assets": { "logo_horizontal": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" } }, "slides": [ { "type": "cover", "slots": { "headline_label": "API GUIDE", "headline": "실패 없는 렌더 요청", "subtext": "manifest부터 차례로 확인한다" } }, { "type": "content-stat", "slots": { "headline": "검증은 요청 전에", "emphasis": "3단계", "body": "슬라이드 수, 필수 슬롯, 값 형식을 순서대로 검사한다" } }, { "type": "cta", "slots": { "headline": "첫 렌더를 시작하세요", "subtext": "이 예시를 복사해 바로 호출한다", "cta_text": "예시 저장하기", "tag1": "API", "tag2": "자동화", "tag3": "카드뉴스" } } ] } ``` ## 6. curl 호출 예시 ```bash curl -X POST 'https://api.cardnews.example/v1/renders' \ -H 'Authorization: Bearer $CARDNEWS_API_KEY' \ -H 'Content-Type: application/json' \ --data-binary @slides.json ``` ## 7. 검증·경고 대응 가이드 - `slide_count_violation`: `cover`와 `cta`는 각각 1장, 나머지 타입은 manifest 범위에 맞춘다. - `required_slot_missing`: 오류의 `path`에 표시된 슬롯을 문자열로 채운다. - `max_chars_exceeded`: 응답의 `hint`에 나온 길이 이하로 문구를 줄여 다시 요청한다. - `text_overflow`: 해당 슬롯을 짧게 쓰거나 문장을 다음 슬라이드로 나눈다. - `invalid_asset_data_uri`: 이미지 값을 공개 HTTPS URL 또는 올바른 `data:image/;base64,...` 형식으로 바꾼다. 실사진은 전체 JSON 본문 1MB 상한을 피하도록 원격 HTTPS URL을 사용한다. - `low_resolution`: 표시 영역보다 큰 원본 이미지로 교체한다.