Figma 조립 패턴 — 부품을 놓은 뒤 화면을 짓는 법
부품 선택(consumption)과 등급(workflow §4)을 지켜도 같은 부품을 페이지마다 다르게 조립하면 마감이 갈린다. 이 문서는 그 **저작 선택을 한 번만 정한다**:
제품 테마 우선: 이 문서의 기본 크기·형태·색·하우스 스타일은 출발점이다. 전체 테마와 component/variant/size/state/slot/instance override를 허용한다.
cc-designer:coui-product-style의references/brand-theme-workflow.md에 기록한 제품 계약으로 판단하며 기본값과 다르다는 이유로 실패 처리하지 않는다.
부품 선택(consumption)과 등급(workflow §4)을 지켜도 같은 부품을 페이지마다 다르게 조립하면 마감이 갈린다. 이 문서는 그 저작 선택을 한 번만 정한다: 행·카드(§C1·§C2) · 위계(§C3) · 공통 셸(§C4) · 표(§C5) · 스크롤 행(§C6) · 터치(§C7) · 이미지 자리(§C8) · 선·면·깊이(§C9) · 글자·숫자 자리(§C10). 결함마다 검사를 더하지 않고 결정적인 부분은 값 하나로 고정하며, 라이브러리가 못 받쳐 주는 곳의 우회에는 만료 조건을 단다.
읽는 법 — 실측이 없는 동작은 (미검증) 이다. (미검증) 연산은 시험하지 않고 consumption §7 의 대체 처리(자연 높이·위 정렬·known-gap)를 쓴다. 인스턴스를 만지는 방법은 consumption §7, 스펙과 부품이 충돌할 때는 §8 이고 여기는 어떤 값·형태로 할지만 정한다. 색과 간격은 제품 테마에 등록한 브랜드·컴포넌트 토큰에서 가져온다(consumption §1·§3). 지켜졌는지는
확인줄을 노드 값으로 읽는다(눈대중 금지). 등급은 design-self-check 가 다루는 항목(리터럴 · 화면 간 일관성 · 스크롤 행)은 그 등급, 마감도는figma-quality-rubric.mdD1–D4 가 가르고, 나머지확인은 보고에 값으로 남긴다(등급 없음). 하우스 스타일 — CoUI 서비스는 기본이 하우스 스타일이다(figma-direction.md§D2에서 판정). §C4 콘솔 셸 · §C8 · §C9 는 각 절의 「하우스 스타일」 줄이 이긴다. 끈 서비스(하우스 스타일: 없음)는 그 줄들을 적용하지 않고 본문 규칙 그대로다.
§C1. 행·카드 인셋과 슬롯 정렬#
-
규칙 — 외곽선이 있는 행·카드 부품(Basic 등)은 안쪽 여백 4변을
space/16(화면 거터와 같은 값)으로 바인딩하고, 목록 행은 인스턴스 루트counterAxisAlignItems='CENTER'(leading·trailing 함께 가운데)로 둔다. trailing 이 위에 붙어야 하는 행의 대안은 consumption §7 정렬 행이다. 높이는 본문 + 패딩으로 늘어나므로(consumption §7) 고정 높이로 자르지 않는다. Mobile 프레임도 같다 — 높이 844 는 기본이고 본문이 더 길면 늘려서 다 보이게 한다. 화면 좌우 거터는 한 값 — Mobile 은space/16, Web 은 콘솔 셸 템플릿(§C4)의 값. 풀블리드 행(§C6)은 패딩 안에 못 들어가므로 Mobile 골격 템플릿 본문의 좌우 패딩은 0 이고, 거터는 풀블리드가 아닌 자식을 묶은 래퍼가 가진다. -
확인 — 외곽선 있는 행·카드(표는 §C5)에서만: 행 루트 padding 4변이 변수 바인딩이고 값 > 0 ·
|leading 중심 − body 중심| ≤ 1px· 어떤 자식도 루트 안쪽 경계에서 0 떨어져 있지 않다 · Leading Checkbox 는Size=xs가 아니다(§C2).
// 행 표준화 — 파라미터: SPACE16 = search_design_system(includeLibraryKeys=[CoUI 라이브러리 키], "space/16") 의 variable key
const sp = await figma.variables.importVariableByKeyAsync(SPACE16);
for (const f of ['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom']) row.setBoundVariable(f, sp);
row.counterAxisAlignItems = 'CENTER';
const cy = n => n.absoluteBoundingBox.y + n.absoluteBoundingBox.height / 2;
return { h: row.height, off: cy(row.findOne(n => n.name === 'leading')) - cy(row.findOne(n => n.name === 'body')) }; // 기대: off ≈ 0
§C2. 체크박스 슬롯#
Leading 에 Checkbox 를 넣을 땐 Size=md 이고 나머지 축이 기본값인 variant 를 이름으로 골라 INSTANCE_SWAP 에 준다(consumption §7 슬롯 부품 교체 행). 라벨 칸이 항상 그려지므로 행 제목이 라벨 역할이면 라벨 글자를 비운다.
§C3. 위계와 타입 스케일#
-
① 글자는 라이브러리 텍스트 스타일만 쓰고 크기는 스타일에서 읽는다(저작자 소유 TEXT — 라이브러리 인스턴스 안쪽 글자는 제외 — 에 스타일 없는 것 0). 줄을 넘기는 한글은 어절 경계에서 꺾는다(
figma-slop-tells.md§S11). 저작자 소유 고정 문구(면책 등)는 한 걸음 더 — 문장·구 경계에서 나누고, 그 줄바꿈은 LF(Enter)로 넣는다(§S11 ③). - ② 화면마다 제목 단계가 하나 있고 카드·행 제목보다 타입 스케일로 한 단계 이상 크다.
- ③ 강조는 중요도 순이다 — 가장 강한 Variant·색은 주 행동에, 보조 요소는 눌림 단서(경계·틴트)가 있는 Variant 중 가장 약한 것에 둔다(가장 무거운 컨트롤은 화면에서 주 행동 하나뿐이어야 한다 — 배너·Alert 안 버튼도 보조 요소로 보고 크기만 §C7).
- ④ 상태 구분은 색이나 굵기 한 가지에 맡기지 않고 단서를 둘 이상 쓴다. 주 행동의 활성 여부는 같은 프레임의 필수 입력 상태와 맞춘다(상태 프레임을 더하지 않는다).
- 확인 — 노드 fontSize 로 화면 제목/행 제목 크기를 읽고, 저작자가 조립한 상태 구분은 색 변수와 굵기·아이콘·모양 중 둘 이상이 다르고(라이브러리 컨트롤 자체의 상태는 부품 몫이라 제외), 주 행동 활성 여부가 같은 프레임의 필수 입력 상태와 같다.
§C4. 공통 셸 — 배너·앱바·하단 탭바·콘솔 셸#
여러 화면에 나오는 셸은 화면마다 짓지 않고 한 번 짓는다(순서·배리어는 design.md Step 1.7). 도메인 컴포넌트는 900 components 의
{domain}/(consumption §4)에 두고 변주는 property 로 한다 —
안쪽 라이브러리 텍스트는 도메인 property 로 올릴 수 없으므로 소비 쪽이 그 안쪽 인스턴스에 setProperties 로 넣는다(Tone 같은 상위 변주를 바꾼 뒤).
Empty·Error 프레임은 모두 이유 한 줄(설명)과 다음 행동 하나(액션)를 둔다 — 아이콘+제목만 두지 않는다.
| 요소 | 표준 형태 |
|---|---|
| 고지 배너 | 컴포넌트 1개, Tone(info·warning)은 property. Banner 는 가장 약한 강조 variant(축 이름·값은 라이브러리에서 읽는다) · Message 한 줄만 |
| 앱바 | AppBar 인스턴스 하나 — Variant 는 앱 전체 한 값이고 조정자가 Figma 라이브러리 기본 Variant 로 정해 DDR 에 적는다(디자이너가 정하기 전까지 잠정). 루트(탭바 항목이 가리키는 화면)는 뒤로가기 없음, 하위(다른 화면에서 눌러 들어가는 화면)는 뒤로가기. 제목을 Child 슬롯에 넣지 않는다. 텍스트 액션이 안 들어가면 consumption §8 |
| 하단 탭바 | 컴포넌트 1개 — 안에 NavigationBar bar 형태, slot 수 = 스펙 탭 수, 라벨·아이콘을 여기서 한 번만 넣고 Selected 만 variant 로 바꾼다(선택 표현은 부품 기본 그대로 — 재바인딩하지 않는다). 라벨은 consumption §7 글자 행을 따른다 |
| 콘솔 셸 | 템플릿 프레임 1개(900 components): 세로 — 배너 전폭 → 가로 본문 [사이드바 NavigationBar sidebar 형태 폭 240 + 메인(상단 바 행 → 본문 — 상단 바 아래 선은 AppBar 기본값 하나)]. 본문 거터·패딩은 한 값. 사이드바는 자연 높이 + 위 정렬로 둔다 — 프레임 높이로 늘리면 안쪽이 세로 가운데로 뜬다. 안쪽 NavigationBar 의 칠·선은 부품 기본값 그대로 둔다(§C9 ③). 템플릿은 컴포넌트가 아니라 프레임이라 화면마다 복제해 쓴다 — 복제본의 구조·바인딩이 같고 라이브러리 기본 문구가 남지 않았는지로 일관성을 본다(self-check 10번) |
| 기기 크롬 |
라이브러리
999. Screen
아래 상태 표시줄 · 홈 인디케이터 · 키보드 부품을 '상태 표시줄' · '홈 인디케이터' · '키보드' 로 검색해 인스턴스로 쓴다. 상태 표시줄은 맨 위(고지 배너 위), 홈 인디케이터는 맨 아래에 폭 FILL(390 폭에서 맞음 — 시험 확인). 기기 크롬 부품의 Device 축(있는 것만)은 앱 전체 한 기기 형태로 맞추고 DDR 에 적는다(잠정). 키보드는 입력 포커스 상태 프레임에만 쓴다
|
-
하우스 스타일 — 상단 바 아래 선 · 사이드바의 칠과 본문 쪽 가장자리 선은 위 규칙대로 부품 기본값 그대로다(면 규칙의 정본은
cc-designer:coui-product-style의 references/token-usage.md 2절). 페이지 머리는 AppBar 가 아니라900 components의promote/PageHeader로 짓는다(어느 서비스에나 필요해 consumption §4 판정이promote/이다 —{domain}/도메인 컴포넌트가 아니다). 값과 근거는cc-designer:coui-product-style의 references/layout.md 1 · 2-1절. 앱바 Variant 는 폭으로 정한다 — Web 프레임standard, Mobile 프레임compact. 앱바 행의 '앱 전체 한 값' 은 같은 플랫폼 프레임 안에서 지키고, Step 1.7 의 공통 요소 목록에 앱바를 플랫폼별로 따로 적어 self-check 10번이 그 안에서 비교하게 한다.
§C5. 표 — 한 파일에 표 스타일은 하나#
-
규칙 — 제품 표(Badge·Button 셀이 있거나 4열 이상)를 라이브러리 Table 이 못 그리면 공유 제품 컴포넌트 하나
promote/DataTable(범용 부품이라 consumption §4 판정은 promote/)을 900 components 에 짓고 모든 화면이 그 인스턴스를 쓴다. 한 표라도 Table 로 못 그리면 그 파일의 표는 전부 공유 컴포넌트다 — 라이브러리 Table 과 직접 조립한 표를 섞지 않는다. 값은 §C9 값·§C3 텍스트 스타일을 따른다. 셀은 CoUI Badge·Button 인스턴스 + 컴포넌트 소유 TEXT 노드(property 결선). 열 수가 화면마다 다르면 열 수별 variant, 행은 SLOT property 에 행 인스턴스를 쌓는다(제안 구조 — 달라지면 DDR). -
확인 — 모든 화면 프레임의 표가 같은 mainComponent · 같은 파일에
Table인스턴스와 공유 표가 공존하지 않음 · 헤더·행·선·반경이 프레임 간에 같다.
§C6. 가로 스크롤 행#
-
규칙 — 항목이 폭을 넘는 행(날짜 칩 7개 · 상태 칩 7개)은 스크롤 행으로 짓는다: ① 프레임 폭 전체(좌우 풀블리드) 컨테이너, 이름
scroll-row · {내용},clipsContent=true, 시작 패딩 = 화면 거터(§C1) ② 항목은 스펙의 개수 전부 — 넘치는 항목을 지우지 않는다 ③ 스크롤 단서: 오른쪽 끝에서 항목 하나가 프레임 가장자리에 잘려 보인다(총 폭 > 컨테이너 폭, 마지막 보이는 칩이 가장자리 6px 안에서 딱 끝나지 않게). 총 폭이 다 들어가면 스크롤 행이 아니다 — 이름·clip 을 쓰지 말고 일반 행으로 둔다. 페이드 그라데이션은 brand-bind 가 다루지 않으므로 쓰지 않는다. -
확인 —
scroll-row노드마다 clipsContent=true 이고 자식 우측 끝 > 컨테이너 폭 — design-self-check 4번은 이 이름의 행만 overflow 에서 제외한다.
§C7. 터치 타겟 (Mobile)#
눌리는 요소의 터치 영역 높이 ≥ 라이브러리 a11y/touch-target(권장 그린 크기, 강제 아님 — Figma px 기준, 스펙이 더 크게 정하면 스펙). ①
그 이상인 Size 를 고른다 — 크기는 라이브러리에서 읽는다. ② 행·카드 안의 작은 요소는 행 전체가 터치 영역이다.
행 안의 별도 동작 버튼은 lg 로 두고 조용한 인상은 Variant 로 낸다(§C3 ③). ③ 단독 요소가 그래도 그 미만이면 크기를 오버라이드하지 말고 실측값을 DDR 에 적어 상류(consumption §6)로 보낸다. Web 콘솔과 배너·Alert 안 버튼(Size 는 부품 기본 그대로)은 적용하지 않는다.
§C8. 이미지 자리#
스펙이 이미지를 아직 올리지 않았으면 눈에 보이는 면을 둔다 — 투명·빈 슬롯 금지. 이미지가 있는 카드는 라이브러리 CardImage
를 쓰고(스펙이 요구한 본문을 못 담으면 consumption §8 대안 표현) Image 속성(INSTANCE_SWAP)에 공유 컴포넌트 promote/ImagePlaceholder(fill
color/surface-container · 가운데 아이콘 · 비율 variant — 루트 종횡비 잠금, 900 components)를 넣는다 — 카드 폭을 채운다. 라이브러리 기본 Image 슬롯은 비어 보이므로 쓰지 않는다.
이미지 자리와 본문은 한 외곽선 안의 한 객체여야 하므로 인스턴스 루트 오버라이드(consumption §7)로 gap 0 · clip · 반경 = 카드 반경 · 선
color/outline-variant 1px 를 두고 본문 행의 선·반경은 끈다.
이미지 자리는 반경 0 으로 두어 루트 clip 이 윗모서리를 깎게 한다(독립으로 놓일 때만 자기 반경). Card 의 Media 슬롯은 안쪽 자리 크기가 잠겨 폭을 못 채우니 이미지 카드에 쓰지 않는다 — 라이브러리 결함(consumption §6).
비율은 스펙이 정하면 그것, 아니면 같은 종류의 이미지는 한 비율로 통일한다(값은 DDR).
-
하우스 스타일 — 이미지 카드 루트에 선 1px 를 얹지 않는다. 루트 오버라이드는 gap 0 · clip · 반경 = 카드 반경만 두고, 한 객체로 읽히는 일은 이미지 자리(위쪽 경계)와 카드 기본 면(
filled)의 톤이 맡는다(cc-designer:coui-product-style의 references/token-usage.md 2절).
§C9. 선·면·깊이#
-
규칙 — ① 정적 컨테이너(Card·Stat·표)의 면과 선은 부품 기본값 그대로다 — 인스턴스 안의 면 · 선을 재바인딩하지 않는다(카드 · KPI 는
filled의 톤, 표 행 구분은color/outline-variant. 선이 없던 안쪽 노드에 새 선을 얹으면 +2px 라 하지 않는다). 면 규칙의 정본은cc-designer:coui-product-style의 references/token-usage.md 2절이다. 스펙이 선 토큰을 정했으면 스펙을 따른다. ② 컨트롤(Button·Chip·Input)의 경계는 라이브러리 기본 토큰을 그대로 둔다 — 눌린다는 단서이고, 장식 선은 컨트롤에 쓰지 않는다. ③ 화면 바탕은 Scaffold 기본값(color/surface), 카드 · KPI 와의 구분 신호는 부품 기본 면(filled)의 톤이다 — 면을 직접 만든 컨테이너를 두지 않고(Card · Stat 인스턴스로), 선과 면 대비를 겹치지 않는다(사이드바 ·outlined카드는 부품 기본값 그대로). ④ 정적 컨테이너의 반경은 라이브러리 Card 의 값 하나다(숫자는 실행 때 라이브러리에서 읽는다) — 값이 다른 Basic·표는 루트 반경으로 맞춘다. ⑤ 그림자는 높이(층) 신호다 — 떠 있는 요소(Toast·Dialog·Popover·FAB)는 서비스와 무관하게 부품이 가진 것을 그대로 둔다. 같은 층의 카드·표만 브리프(figma-brand-selection.md§1)의 '카드 깊이' 칸이 키워드에서 도출하고 저작자는 그 칸을 따른다. '카드까지'이면 카드·표 루트에 라이브러리 효과 스타일(shadow/*)을 적용하고(consumption §7 — 단계는 DDR 에 적는다), 평면이면 얹지 않는다. -
하우스 스타일 — ①③ 은 위 규칙 그대로다(같은 정본을 인용한다). ④ 패널 컨테이너 · Card · Stat 는 Card 값 하나이고, 카드 안 표 · 입력 · 버튼은 부품 기본 반경 그대로다. ⑤ 브리프 '카드 깊이' 는
평면이다. 슬롭 지문 §S1 이 카드 안 선택 · 호버 행을 안쪽 면으로 세면 고치지 않고 L1 로 두며, 사유는 「하우스 스타일: 부품의 상태 면」 한 줄이다. 값과 근거는cc-designer:coui-product-style의 references/token-usage.md 2 · 3절 · layout.md 7 · 8절. - 확인 — 정적 컨테이너(Card · Stat · 표)의 면 · 선 변수가 부품 기본값 그대로(재바인딩 0) · 컨트롤 경계 변수 이름은 라이브러리 기본 그대로 · 면을 직접 만든 컨테이너 0 · 선과 면 대비를 겹친 컨테이너 0(사이드바 · 선으로 두르는 카드 · Banner · 앱바 · 하단 탭바의 부품 기본 선 · 면 제외) · 정적 컨테이너 반경 값이 하나 · 저작자가 얹은 효과 스타일은 카드·표 루트에만 있고 브리프 '카드 깊이'와 일치(평면이면 0). 하우스 스타일이면 위 「하우스 스타일」 줄을 기준으로 읽는다.
§C10. 글자·숫자 자리 — 샘플 콘텐츠#
스펙이 문구와 값을 다 주지 않으므로 시안의 글자 대부분은 저작자가 채운다. 그 샘플이 화면을 '어느 서비스나'로 만들거나, 지어낸 숫자를 사실처럼 퍼뜨린다.
-
규칙 —
① 스펙이 준 문구·수치는 그대로 쓴다(스펙 수치 체크리스트 — design.md Step 1). 단 스펙 문구 안에서 그 문구 자체의 지위를 말하는 메모는 문구가 아니다 —
예:
데모 문구·예시·가안·임시·문구 미정·TBD. 목록이 아니라 '문구에 대한 말인가'로 판정한다(… 강사에게 알리세요 — 데모 문구의— 데모 문구). 메모를 뺀 문구를 그리고, 뺀 메모는 DDR 과 보고의 스펙 수정 제안에 남긴다. 메모를 빼면 남는 문구가 없으면(문구 전체가문구 미정) 그 자리는 ② 로 채운다. 사용자에게 하는 고지 — 데이터가 가상이거나 체험용이라는 표시(가상·데모 값·체험용 데모) — 는 메모가 아니라 문구다. ③ 의 '수치 확인 필요'는 이 메모가 아니다 — 스펙 문구에 붙어 새어 나온 말이 아니라 값이 없는 자리에 파이프라인이 일부러 세우는 표지이고, 보이는 것이 목적이다. 둘 다 스펙 쪽이 채울 자리라 보고의 스펙 수정 제안에 함께 싣는다(메모는 '문구 확정 필요', 표지는 '값 필요'). ② 스펙이 비운 자리는 그 서비스에서 실제로 나올 법한 값으로 채운다. 목록에는 길이가 다른 값을 섞고(짧은 이름과 긴 이름, 줄이 넘칠 만큼 긴 제목 하나 이상 — 넘친 줄은 어절 경계에서 꺾는다, slop-tells §S11), 경계값을 하나 이상 둔다(0건 · 마감 · 대기 · 큰 금액처럼 레이아웃을 시험하는 값). ③ 비율 · 배수 · 증감 · 평점 · 누적 이용자 같은 지표 수치는 스펙에 없으면 쓰지 않는다. 자리가 꼭 필요하면—와 '수치 확인 필요'를 쓴다. ④ 흔한 가명 · 더미 문구 · 부품 기본 문구를 남기지 않는다(목록 —figma-slop-tells.md§S6). ⑤ 한 프레임 안 문구의 높임 수준은 하나다. 조사는 값에 맞춰 하나로 정한다 — '을(를)' 같은 병기를 남기지 않는다. ⑥ 그림 문자로 아이콘을 대신하지 않는다 — 라이브러리 Icon 인스턴스를 쓴다. ⑦ 값이나 구절을 대시 · 가운뎃점으로 이어 붙여 구분하지 않는다 — 자리를 나누고 간격 · 줄바꿈으로 구분한다(인스턴스 안 글자는 slop-tells §S10 「고치는 법」). 스펙이 준 문구는 ① 이 먼저다. - 왜 — 뻔한 샘플은 검토자가 그 자리의 실제 데이터를 떠올리지 못하게 한다. 실제 데이터는 길이가 제각각이고 경계값이 있으며, 그것이 레이아웃이 버티는지 시험한다 — 같은 길이의 샘플만 있으면 넘치는 화면을 시안 단계에서 볼 수 없다. 지어낸 지표 수치는 시안을 본 사람이 사실로 기억해 기획에 역류한다. 스펙 문구를 '그대로' 쓰라는 ① 이 문구에 붙은 메모까지 옮기게 하면 그 메모가 제품 문구가 된다 — 실제로 안전 안내 끝의 '— 데모 문구'가 화면에 그대로 그려져 블라인드 평가에서 짚혔다.
-
확인 — ① 의 저작 메모와 ③–⑦ 은
figma-slop-tells.md§S5–§S10 의 레시피 결과(design-self-check 11번 — 메모는 §S6memo), 긴 값의 줄바꿈은 §S11. ② 의 길이 섞기 · 경계값은 목록·표 화면마다 긴 값과 경계값이 어느 노드인지 보고에 남긴다(등급 없음 — 위 읽는 법).