/cc-blueprint:build — Figma 시안에서 화면 코드까지 (데이터레이어 없이)
레지스트리에 등재된 Figma 프레임을 데이터레이어 없는 기능모듈(Page·Widget·BLoC + 도메인 계약 인터페이스 + mock 주입)로 구현해, 위젯북 use_case 등재·상태 4종 골든 스냅샷·상태 프레임마다 라이트 · 다크 Figma 대조(결정적 픽셀 비교)·검증 체크리스트 통과 기록을 남깁니다. 백엔드가 아직 없는 화면을 기획·디자인 ...
| 항목 | 내용 |
|---|---|
| 실행 명령 | /cc-blueprint:build |
| 분류 | cocode design |
| 난이도 | ●●○ 보통 |
| MCP 서버 | figma |
한마디로#
Figma 시안을 주면 실제 앱 화면 코드로 구현하되, 서버·DB 같은 데이터 부분은 만들지 않는 명령입니다. 화면은 "데이터가 이렇게 생겼다"는 계약(인터페이스) 과 가짜 데이터(mock) 위에서 돌아가므로, 백엔드 개발 전에 위젯북 전시장에서 상태별(Default/Loading/Empty/Error)로 눌러보고 피드백을 받을 수 있습니다. 나중에 백엔드가 준비되면 가짜 데이터 자리에 진짜 구현만 끼우면 됩니다(bricks 흡수 용이).
누가·언제 쓰나요#
/cc-blueprint:design으로 시안이 나왔고 화면 코드를 시작할 때- 백엔드 일정과 무관하게 화면 먼저 검증(기획·디자인 피드백 루프)하고 싶을 때
- 화면 모듈을 이후
cc-bricksfeature 모듈 구조로 흡수하기 쉽게 만들고 싶을 때
무엇을 해주나요#
- Figma 프레임을 읽어 화면 모듈(페이지·위젯·상태 관리)을 CoUI 표준 부품으로 구현합니다
- 데이터는 계약 인터페이스 + mock 공급자로 대체합니다 — Repository 구현·API·DB 는 만들지 않습니다
- 화면을 위젯북에 등재하고 상태 스위치(Knob)가 실제로 동작하게 배선합니다
- 상태별 골든 스냅샷(비주얼 회귀 기준)을 만들어 이후 변경이 화면을 깨면 테스트가 잡아냅니다
- 상태 프레임마다 밝은 · 어두운 테마로 시안과 앱 화면을 프로그램이 점 단위로 비교해, 같아야 완료라고 말합니다 — 다른 곳은 앱 코드 · 스타일 · CoUI 버전 차이 · 알려진 차이 중 어디서 고칠지 먼저 가립니다
- 끝나면 검증 체크리스트(데이터레이어 0 · 계약+mock · 등재 · 스냅샷 · Figma 대조)를 통과했는지 스스로 확인합니다
어떻게 쓰나요#
# 레지스트리에 등재된 섹션 하나를 구현
/cc-blueprint:build --frames "상품 목록" --app {앱 워크스페이스 경로}
# 여러 섹션 일괄 + 대상 feature 워크스페이스 지정
/cc-blueprint:build --frames "상품 목록,상품 상세" --app {앱 워크스페이스 경로} --feature store
안에서 무슨 일이 벌어지나요#
-
입력 검증 — 프레임이 레지스트리에 등재돼 있는지, (권장)
design-self-checkL0 = 0 인지, 프레임에 고정한 브랜드 · 서페이스 스타일 · 밀도가 하나로 맞는지 확인하고 그 값을 앱 설정(CoUIApp)으로 옮깁니다. 시안이 쓰는 서체가 앱에 있는지, 앱이 실제로 쓰는 CoUI 판이 무엇인지도 여기서 확인합니다. - 시안 읽기 — Figma 에서 레이아웃·토큰·컴포넌트 구성을 추출합니다.
- 모듈 스캐폴드 — 페이지·위젯·BLoC + 도메인 계약 + mock 공급자 골격을 만듭니다.
- CoUI 구현 — 표준 부품과 토큰으로 화면을 조립합니다.
- 위젯북·회귀 배선 — use_case 등재, 상태 Knob, designLink 결합, 골든 스냅샷, 그리고 시안과 같은 크기로 상태마다 찍는 대조용 캡처.
- 검증 체크리스트 — Figma 대조를 포함한 5항목 통과를 확인하고 결과를 보고합니다.
⚙️ 상세 옵션·실행 명세 (개발자 / AI 에이전트용)
Usage#
/cc-blueprint:build --frames "{섹션}[,{섹션}...]" --app {path} [--feature {name}] [--surface {surface}]| 옵션 | 설명 |
|---|---|
--frames | 구현할 섹션(레지스트리 등재분). 상태 프레임은 섹션 단위로 전부 읽는다 |
--app | 대상 앱/모노레포 워크스페이스 경로 |
--feature | feature 모듈 이름 (기본: 섹션이 속한 Page 이름의 snake_case) |
--surface | 레지스트리 3단 대응의 [Surface] (기본: 레지스트리 행에서 읽음) |
Step 0: Input Validation#
1. 레지스트리 대조 — --frames 의 각 섹션이 화면 레지스트리에 등재돼 있는가
(미등재 프레임은 정본이 아니다 — rules/figma-workflow.md §1). 미등재 → 그 섹션 SKIPPED
+ "/cc-blueprint:design 으로 등재 후 재실행" 안내.
2. (권장) skills/design-self-check 를 입력 프레임에 적용 — L0 프레임은 구현 입력으로 받지
않는다(시안 결함을 코드로 복제하는 것을 막는다). L0 발견 시 그 섹션 SKIPPED-BLOCKED
(blockedBy 시안 재작업). 단 L0 가 3번(토큰 단일 출처)의 **리터럴 색뿐**인 프레임은 받는다 —
코드는 토큰으로 칠하고 리터럴 덧대기는 Step 5 의 대조가 막으므로 그 결함이 코드로 복제되지
않는다. 그 프레임의 다른 밝기 대조만 5번 · Step 5 에서 판정 불가로 남아 디자이너에게 간다.
3. 브랜드 테마 + 컴포넌트 스타일 → 앱 적용
- 브랜드 manifest의 source/revision, 외부 alias, 상속 override, mode와 타입/단위를 해석한다.
같은 snapshot의 JSON/Dart/CSS를 쓰고 전체 테마뿐 아니라 component/variant/size/state/slot/instance
override도 실제 resolver에 매핑한다. 토큰 상수 생성은 런타임 적용 완료가 아니다.
- 현재 API가 없는 속성은 adapter/API 확장 gap으로 기록하고 구현 범위 안에서 해결한다.
아래 frame-modes 출력만으로 전체 테마를 읽었다고 판단하지 않는다.
프레임 모드 → 앱 인자 — references/recipes/frame-modes.figma.js 를 섹션의 화면 프레임
전부에 돌린다(페이지마다 한 번). 반환 app 의 brand · surfaceStyle · density 가 앱 루트
CoUIApp 의 인자다(cc-flutter:figma-to-coui 「Figma → CoUI 번역 명세」 F5).
- app 이 null(blocking — 고정한 값이 프레임마다 다르다 · 이름을 읽지 못했다) → 그 섹션
SKIPPED-BLOCKED (blockedBy 시안 결함 · 디자이너 확인). 앱이 한 벌인 값을 화면마다 고르지 않는다.
- warnings(색 모드를 고정하지 않은 프레임) → 진행하되 보고에 싣는다 — 그 프레임은 다크
확인에서 따라오지 않는다.
- 브랜드 → 앱 테마 모듈의 CoreBrand(id 또는 displayName 이 brand 와 같은 것). 없으면
SKIPPED-BLOCKED (blockedBy 브랜드 정의 — demo-brand-theme 또는 제품의 테마 모듈).
시안의 hex 로 시드를 짐작하지 않는다.
- 레버 DDR(rules/figma-direction.md §D2)의 브랜드 속성도 옮긴다 — 서체 역할은
ThemeData(typography: CoreTypography.coui.withFamily(…)), 라이브러리가 모드로 싣지 않은
형태 · 재질 · 테마 밀도는 그 값의 CoUIApp 인자.
- 앱 루트의 CoUIApp 이 이 값과 다르면 화면 모듈에서 고치지 않고 보고한다 — 앱 전체의
값이라 어느 쪽이 맞는지는 디자이너 · 앱 소유자가 정한다.
4. 제품 컴포넌트 판정 — 섹션이 라이브러리 밖 컴포넌트(제품이 이름 붙인 것)를 쓰면, 시안 파일의
컴포넌트 ↔ CoUI 비교 시트를 references/recipes/compare-sheet.figma.js 로 읽는다(시트마다 한 번).
컴포넌트마다 판정 · CoUI 대응 · 조립 부품을 찾아 cc-flutter:figma-to-coui F8 의 행동으로 옮긴다.
- issues 가 비어 있지 않으면 그 표를 쓰지 않는다 — 해당 컴포넌트는 판정 없음으로 다루고 보고한다.
- 판정 없음(시트에 없다 · 시트가 없다) → 판정을 쓰지 않는다. 디자이너에게 요청하고 임시 경로로 진행 — 차단 아님.
- 판정이 요구한 CoUI API 가 앱의 CoUI 릴리스에 아직 없으면(F9 의 버전 표시) 들어오기 전 경로 + 만료 조건.
5. 대조 입력 · 서체 · CoUI 판 — Step 5 의 Figma 대조를 지금 준비한다(cc-pixel-loop:visual-verify §2 · §7).
references/recipes/compare-frames.figma.js 를 섹션마다 돌려 반환을 frames-<섹션>.json 에 저장하고,
figma_compare.py plan · fonts · coui 를 돌린다(실행 폴더 .claude/docs/visual-verify/<run_id>/).
- coui = 앱이 해석한 CoUI 릴리스(.dart_tool/package_config.json · pubspec.lock) 와 라이브러리 사이에서
달라진 컴포넌트. **버전 판단은 이 값으로 한다** — 4번의 「앱의 CoUI 릴리스」, F9 의 버전 표시,
「아직 없는 CoUI API」 모두. 스킬 저장소의 기준(coui_skills_basis)은 앱의 판이 아니다.
drift 의 컴포넌트에서 나는 차이는 Step 5 에서 `version` 으로 판정될 자리다 — 화면 코드로 맞추지 않는다.
- fonts 실패(시안의 서체가 앱 · 의존 패키지에 선언되지 않았다 · 테스트가 로드하지 않는다) → 진행하고,
Step 4 에서 서체를 번들 · 로드한다. 그 전의 대조는 판정 불가다(다른 서체로 떨어진 렌더는 비교할 수 없다).
- plan 의 원천이 unthemable(시안 색이 변수에 묶이지 않음 — design-self-check 3번 토큰 단일 출처 L0) →
진행 + 보고. 그 밝기의 대조는 판정 불가로 남아 디자이너에게 간다. 앱 코드로 다크를 짐작해 맞추지 않는다.
- 이름이 「플랫폼-상태」 가 아닌 프레임은 비교 목록에 들지 않고 요약을 판정 불가로 만든다 — 옛 파일이면 레시피의 NAMES,
섹션 안의 화면이 아닌 프레임(메모 류)이면 plan 의 --ignore-frame '<id>=<이유>', 아니면 디자이너에게 이름을 요청.Step 1: Figma 읽기 (위임)#
figma:figma-design-to-code 스킬을 로드하고 get_design_context 로 섹션의 상태 프레임
전부를 읽는다 — 파라미터 규약·응답 형태는 그 스킬/도구가 SoT.
Step 2: Module Scaffold — 프레젠테이션 온리 계약#
모듈 구조는 cc-bricks 로스터의 Clean Architecture feature 모듈과 같은 자리·같은
이름을 쓰되, data 레이어 디렉토리를 만들지 않는다:
feature/{location}/{feature_name}/
├── domain/
│ ├── entity/ # 화면이 소비하는 Entity (시안에서 추출한 필드)
│ └── repository/ # ⭐ 계약 인터페이스만 — 구현체 없음
├── presentation/
│ ├── bloc/ # BlocSignal — UseCase 대신 repository 계약을 직접 주입받지 않고
│ │ # 도메인 UseCase 를 거친다 (cc-flutter:package-layers 준수)
│ ├── page/ # Page 는 BLoC 을 this.bloc 선택 주입으로 받는다 (widgetbook mock 가림 방지)
│ └── widget/
├── mock/ # ⭐ mock repository 구현 + 시나리오 데이터 (Default/Loading/Empty/Error)
│ └── {feature}_mock_repository.dart
└── {feature}_widgetbook.dart 등 use_case # feature 소유 (widgetbook-conventions)bricks 흡수 계약 (이 커맨드의 존재 이유):
domain/과presentation/은 이후 bricks data 레이어가 들어와도 변경 0 이어야 한다 — 화면이 mock 을 직접 import 하지 않고, DI 조립부에서만 mock repository 를 계약에 바인딩한다.mock/은 data 레이어 도착 시 통째로 삭제 가능해야 한다 (교체 지점이 DI 1곳).- Repository 구현·API client·DB(Drift)·캐싱은 생성 금지 — 발견되면 검증 체크리스트 실패.
Step 3: CoUI 구현 (위임)#
- 변환 패턴:
cc-flutter:figma-to-coui(12 Use Case) — 페이지 뼈대·폼·로딩·오버레이 등. - 컴포넌트 API 1차 소스:
cc-coui:*(컴포넌트 1:1 스킬). 토큰 하드코딩 금지. - 시안 → 코드 대응은
cc-flutter:figma-to-coui의 「Figma → CoUI 번역 명세」 — 텍스트 스타일 · 변수 · 인스턴스(그 릴리스의components.json) · 효과 스타일 · 프레임 모드 · 사다리 밖 값. 노드 이름으로 위젯을 고르지 않는다. - 캔버스와 렌더가 다르면 고치기 전에 그 명세의 「알려진 차이」(F7)를 먼저 본다 — 해당하면 앱을 고치지 않는다.
- 제품 컴포넌트는 Step 0 의 판정대로(F8), 제품 이름 · 흔한 모양으로 CoUI 를 찾을 때는 F9 이름 찾기 표 — 도메인 전용은 시트의 조립 부품을 합성한다.
- Step 4 의 위젯북 · 골든 래퍼도 Step 0 의 앱 인자(브랜드 · 서페이스 스타일 · 밀도)를 쓴다 — 다른 인자로 찍은 골든은 시안과도 앱과도 같지 않다.
- 상태 표현: Bloc state ↔ 시안의 상태 프레임 1:1 (Default/Loading/Empty/Error — figma-workflow §5 R2 어휘).
- 시안 글자에 넣은 U+2028 줄바꿈은 Figma 의 어절 줄바꿈 보정이라 코드 문자열로 옮기지 않는다. 대신 그 글자는 CoUI
Text체인의.keepAll로 그린다 — 줄을 넘길 수 있는 한글 글자(시안에서 U+2028 이 든 글자 · slop-scanwrap후보였던 글자)에 단다(rules/figma-slop-tells.md§S11).
Step 4: Widgetbook + Visual Regression (분리 가능한 단계)#
skills/widgetbook-wiring 를 로드해 그 절차(배선 5단계 + 4b 대조용 캡처 ·
완료 조건)를 그대로 수행한다 — 기존 화면 소급 등재 시에는 이 Step 만 단독 실행할 수 있다.
규약 SoT(widgetbook-conventions · figma-widgetbook-alignment · golden-test-guide)는 그 스킬이 인용한다.
4b 의 캡처 장치는 Step 0 의 plan 이 정한 프레임 크기 · 배율 · 상태 바다.
Step 5: Verification Checklist (완료 선언 조건)#
□ 데이터레이어 0 — data/ 디렉토리·Repository 구현·API client·DB 코드 부재 (grep 검사)
□ 계약 + mock — domain/repository 인터페이스 존재 · mock/ 이 DI 1곳에서만 바인딩
□ use_case 등재 — 섹션마다 1건, 상태 Knob 동작 (Page 자체 BLoC 생성 없음)
□ 골든 스냅샷 — 상태 4종 × 대표 뷰포트 존재, flutter test 통과
□ Figma 대조 — 등록된 상태 프레임마다 라이트 · 다크로 cc-pixel-loop:visual-verify 의 summary 가 pass
(프레임 크기 · 배율 · textScaler 1.0 · 서체 확인 후). 판정 불가 · 실패는 통과가 아니다 —
밝기 제외는 이유와 함께만(plan --exclude-theme), 면제는 version · known 만(근거를 스크립트가 다시 확인)
□ 시각 다듬기 — cc-flutter:figma-to-coui 「시각 다듬기 체크리스트」 P1–P8(숫자 자리 · 아이콘 세트 · 한국어
줄바꿈 · 모션 별칭 · 차트 색 · 다크 · 글꼴 번들 · 큰 컨트롤). 대조가 pass 여도 남는 자리다체크 실패 항목이 있으면 완료를 선언하지 않고 해당 Step 으로 되돌아간다(섹션당 2회, 이후 실패 보고).
Figma 대조가 fail 이면 남은 영역의 판정(app · style-slot)대로 Step 3 으로 돌아간다 — 고치며 맞추는 반복은
/cc-pixel-loop:loop 와 같다. 리터럴 덧대기는 고침으로 세지 않는다(summary 가 fail:literal-patch).
판정 불가가 시안 쪽 원인(unthemable · 「플랫폼-상태」 이름이 아닌 프레임)이면 되돌아가지 않는다 — 구현 산출물은
남기되 그 섹션의 완료를 선언하지 않고 BLOCKED(blockedBy 시안 결함 — 고친 뒤 /cc-pixel-loop:verify 재실행) 로 보고한다.
코드로 고칠 수 없는 판정 불가를 반복 예산에 쓰지 않는다. 제품이 그 밝기를 내지 않는 결정이면 그 결정 기록과 함께
--exclude-theme '<theme>:<이유>' 로 뺀다.
Output#
## 🧩 구현 결과 — {feature}
| 섹션 | 모듈 경로 | use_case | 골든 | Figma 대조 | 체크리스트 |
|------|-----------|----------|------|------------|------------|
| 상품 목록 | feature/application/store/... | ✅ | 4/4 | pass 8/8 (면제 1) | PASS |
### 앱 인자: 브랜드 {Brand} · surfaceStyle {…} · density {…} (frame-modes) · 경고 {n} · 앱 루트와 차이 {없음|목록}
### 제품 컴포넌트: 시트 판정 {n} · 판정 없음 {n}(디자이너 요청 {링크}) · 아직 없는 CoUI API {n}(임시 경로 · 만료 조건) (compare-sheet)
### Figma 대조: {summary.md 첫 줄} · 앱의 CoUI {패키지 버전 · 커밋} · 라이브러리와 달라진 컴포넌트 {n} · 면제 version {n} · known {n} · 판정 불가 {사유} · 리터럴 예외 {n}
{summary.md 의 표 — PR 본문에 그대로}
### mock 시나리오: {n}종 · bricks 흡수 지점: DI {파일}:{줄}
### 다음 단계: /cc-blueprint:sync (Figma↔Widgetbook 대조) · 데이터레이어: cc-bricks / cc-serverpodError Handling#
| 상황 | 행동 |
|---|---|
| 레지스트리 미등재 프레임 | 그 섹션 SKIPPED + design 커맨드 안내 |
| 입력 프레임 self-check L0 | 그 섹션 SKIPPED-BLOCKED (시안 재작업 선행) |
프레임마다 고정한 브랜드 · 서페이스 스타일 · 밀도가 다름 (frame-modes blocking) | 그 섹션 SKIPPED-BLOCKED (blockedBy 시안 결함 · 디자이너 확인) — 고르지 않는다 |
브랜드의 CoreBrand 가 앱 테마 모듈에 없음 | 그 섹션 SKIPPED-BLOCKED (blockedBy 브랜드 정의) — 시안 hex 로 시드를 짐작하지 않는다 |
앱 루트 CoUIApp 인자가 frame-modes 값과 다름 | 진행 + 보고 — 앱 전체의 값은 화면 모듈이 바꾸지 않는다 |
| 캔버스와 렌더가 「알려진 차이」에 해당 | 앱을 고치지 않고 보고에 그 행의 CoUI 이슈를 적는다 |
| CoUI 에 없는 컴포넌트 | 비교 시트의 판정이 있으면 그 판정(figma-to-coui F8). 없으면 디자이너에게 판정을 요청하고, 그동안 rules/coui-library-consumption.md §4 판정 질문으로 임시 경로 — 조합 대체 → 범용이면 CoUI 승격 후보 표시 후 도메인 위젯으로 구현 계속, 도메인 전용이면 도메인 위젯 — 차단 아님 |
compare-sheet 의 issues 가 비어 있지 않음 | 그 시트의 표를 쓰지 않는다 — 해당 컴포넌트는 판정 없음으로 진행 + 보고 (시트를 고칠 일이면 디자이너에게) |
시안의 서체가 앱에 없음 (fonts 실패) | 서체를 앱 · 디자인 시스템 패키지에 번들하고 캡처 테스트가 로드하게 한다 — 그 전의 대조는 판정 불가 |
| Figma 를 읽지 못함 · 다른 밝기 복제본을 만들 권한이 없음 | 그 대조는 판정 불가 — 통과로 바꾸지 않고 Step 5 를 실패로 보고 |
다른 밝기가 unthemable (시안 색이 리터럴) | 구현은 남기고 그 섹션은 완료 대신 BLOCKED (blockedBy 시안 결함) — 다크를 앱 코드로 짐작하지 않는다. 라이트만 내는 제품이면 그 결정 기록과 함께 --exclude-theme |
| 차이 영역이 앱의 CoUI 와 라이브러리 사이에서 달라진 컴포넌트 안 | version 으로 판정 — 화면 코드로 맞추지 않는다. 앱의 CoUI 를 올리거나(cc-coui-upgrade) 라이브러리를 앱의 판에 맞춘다(coui-library-update) |
대조가 리터럴 덧대기를 찾음 (fail:literal-patch) | 그 수정을 되돌리고 CoUI 부품 · 스타일 슬롯 · 토큰으로 고친다 — 남겨야 하면 그 줄에 // literal-ok: <이유> |
| 체크리스트 반복 실패(2회) | 해당 섹션 실패 보고 + 나머지 산출 (전체 중단 금지) |
Related#
cc-flutter:figma-to-coui·cc-coui:*— 구현 패턴·API SoTcc-flutter:widgetbook-conventions·cc-flutter:figma-widgetbook-alignment·cc-flutter:golden-test-guide— Step 4 SoTcc-pixel-loop:visual-verify— Step 5 Figma 대조의 절차 · 규칙 · 기본값 SoT (/cc-pixel-loop:verify)cc-bricks— 흡수 대상 구조(feature 모듈 로스터)rules/figma-workflow.md·rules/coui-library-consumption.md/cc-blueprint:design(이전 단계) ·/cc-blueprint:sync(다음 단계)