/cc-flutter:ui — 피그마 디자인을 화면 코드로
Figma 디자인을 Flutter UI 컴포넌트로 변환 (CoUI 디자인 시스템)
| 항목 | 내용 |
|---|---|
| 실행 명령 | /cc-flutter:ui |
| 분류 | 개발 |
| 난이도 | ●●○ 보통 |
| MCP 서버 | figma, serena |
한마디로#
디자이너가 그린 피그마 디자인을 보고, 그대로 작동하는 앱 화면 코드(Flutter)로 옮겨주는 도구입니다. 도면(피그마)을 건네면 우리 회사 표준 부품(CoUI)으로 실제 화면을 조립해 주는 셈이에요.
누가·언제 쓰나요#
- 디자이너가 만든 피그마 화면·컴포넌트를 실제 앱 화면으로 만들어야 할 때
- 우리 회사 디자인 시스템(CoUI)에 맞춰 버튼·카드·입력창 같은 UI를 새로 만들 때
- 빠르게
/ui,/coui같은 짧은 별칭으로 호출하고 싶을 때
무엇을 해주나요#
- 피그마 화면을 분석해 우리 표준 부품(CoUI 위젯)으로 바꾼 화면 코드(Widget 파일) 를 만들어 줍니다.
- 색상·글자·간격을 임의로 정하지 않고 회사 디자인 토큰(정해진 색·글꼴·여백 규칙)에 맞춥니다.
- 만든 컴포넌트를 해당 기능 폴더에 배치하고, 컴포넌트 카탈로그(Widgetbook UseCase) 와 테스트 파일까지 함께 만들어 줍니다.
어떻게 쓰나요#
# 버튼 컴포넌트 만들기
/cc-flutter:ui button --name SubmitButton --feature common
# 피그마 카드 디자인을 변환하기 (--figma-node 로 피그마 노드 지정)
/cc-flutter:ui card --figma-node "https://www.figma.com/design/<key>/<name>?node-id=12-345" --name ProductCard --feature store
# 화면 전체를 변환하기
/cc-flutter:ui page --figma-node "https://www.figma.com/design/<key>/<name>?node-id=1-100" --name HomePage --feature home
-
component_type(필수): 만들 종류 —button,card,form,page등 -
--figma-node: 변환할 피그마 노드의 링크 (node-id가 든 Figma URL). 노드 ID 만으로는 어느 파일인지 알 수 없어 Figma MCP 가 읽지 못합니다 --name: 컴포넌트 이름 (예:ProductCard)--feature: 어느 기능 모듈에 넣을지 (예:home,store)
안에서 무슨 일이 벌어지나요#
- 피그마 분석 — Figma 공식 MCP 로 지정한 노드의 구조·색상·텍스트와 렌더 이미지를 읽어 들입니다. 읽지 못하면 코드를 만들지 않고 멈춥니다.
- 부품 매칭 — 피그마 요소를 우리 표준 부품(CoUI 위젯)과 색상·글꼴 규칙에 1:1로 연결합니다.
- 화면 코드 생성 — 연결한 내용을 바탕으로 실제 Flutter 화면 코드를 만들고, 화면 크기에 맞게 반응형으로 구성합니다.
- 프로젝트에 통합 — 만든 코드를 기능 폴더에 넣고, 컴포넌트 카탈로그와 테스트 파일까지 함께 정리합니다.
⚙️ 상세 옵션·실행 명세 (개발자 / AI 에이전트용)
Triggers#
- When converting Figma frames/components to Flutter
- CoUI design system based UI development
- When using the
/uikeyword
Context Trigger Pattern#
/cc-flutter:ui {component_type} [--options]Parameters#
| Parameter | Required | Description | Example |
|---|---|---|---|
component_type | ✅ | Component type | button, card, form, page |
--figma-node | ❌ | Figma node link — a URL with node-id (reading needs the file key) | https://www.figma.com/design/<key>/<name>?node-id=12-345 |
--name | ❌ | Component name | ProductCard |
--feature | ❌ | Feature module | home, store |
Execution Flow#
┌─────────────────────────────────────────┐
│ 1. Figma 노드 분석 (공식 Figma MCP) │
├─────────────────────────────────────────┤
│ • whoami → create_session │
│ • get_design_context (+ 스크린샷) │
│ • get_variable_defs │
│ • get_screenshot │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 2. CoUI 컴포넌트 매핑 │
├─────────────────────────────────────────┤
│ • Figma 클래스 → CoUI 위젯 (bare <X>) │
│ • 색상 변수 → appColors / colorScheme │
│ • 타이포그래피 → context.textStyles │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 3. Flutter 코드 생성 (figma-to-coui) │
├─────────────────────────────────────────┤
│ • 참조 코드(React/HTML)는 옮기지 않고 │
│ CoUI 위젯으로 다시 조립 │
│ • Widget 구조 생성 │
│ • 반응형 레이아웃 적용 │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 4. 프로젝트 통합 │
├─────────────────────────────────────────┤
│ • Feature 위젯 디렉토리에 배치 │
│ • Generate Widgetbook UseCase │
│ • 테스트 파일 생성 │
└─────────────────────────────────────────┘CoUI Design System#
Color Mapping#
Figma 의 시맨틱 색 변수 이름이 곧 ColorScheme 슬롯이다 — color/<슬롯> 의 kebab 을 camel 로.
// Figma 색 변수 → Flutter (context.colorScheme)
color/surface → context.colorScheme.surface.toValue()
color/surface-container-high → context.colorScheme.surfaceContainerHigh.toValue()
color/on-surface-variant → context.colorScheme.onSurfaceVariant.toValue()
color/primary → context.colorScheme.primary.toValue()
// 글자 색은 Text 체인으로: Text('…').onSurfaceVariant
Component Mapping#
| Figma | Flutter/CoUI | Notes |
|---|---|---|
| btn | Button(variant: ...) | no CoButton, no Button.primary() |
| card | Card (slot-based: media/header/body/footer/overlay) | no CoCard, no separate CardHeader/CardFooter widgets |
| input | TextField(type: CoreInputType.x, label: ...) | no Input (0.127.16 에서 제거), no CoTextField, no FormTextField |
| modal | Dialog | no CoDialog |
| drawer | Drawer | no CoDrawer |
| navbar | AppBar (in Scaffold(headers: [...])) | no CoAppBar |
| avatar | Avatar | no CoAvatar |
| badge | Badge(variant: ...) | no CoBadge, no PrimaryBadge |
| tabs | Tabs | no CoTabBar — verify exact API against coui-tabs before use |
| icon | Icon(LucideIcons.x) | no CoIcon, no HeroIcon |
| spacing | Gap.spaceN() / Gap(gapStyle: CoreGapStyle(...)) | no CoGap, no Gap.s*, no Gap(size: CoreSpace.spaceN) (v0.92) |
Typography#
Figma 텍스트 스타일 이름은 역할이다 — Headline/Large 는 Text('…').headlineLarge. 굵기 · 색은 체인을 잇는다(Text('…').titleMedium.onSurfaceVariant).
| Figma 텍스트 스타일 | Text 체인 | 크기 | 굵기 | 행간 | 자간 | 서체 | v2 이전 |
|---|---|---|---|---|---|---|---|
Display/Large | .displayLarge | 52 | 700 | 140% | −2% | 본문 | 같은 이름 |
Display/Medium | .displayMedium | 48 | 700 | 140% | −2% | 본문 | 같은 이름 |
Display/Small | .displaySmall | 44 | 700 | 140% | −2% | 본문 | 같은 이름 |
Headline/Large | .headlineLarge | 32 | 700 | 140% | −2% | 본문 | 같은 이름 |
Headline/Medium | .headlineMedium | 28 | 700 | 140% | −2% | 본문 | 같은 이름 |
Headline/Small | .headlineSmall | 24 | 700 | 140% | −2% | 본문 | 같은 이름 |
Title/Large | .titleLarge | 20 | 700 | 140% | −2% | 본문 | 같은 이름 |
Title/Medium | .titleMedium | 18 | 700 | 140% | −1% | 본문 | 같은 이름 |
Title/Small | .titleSmall | 16 | 700 | 140% | −1% | 본문 | 같은 이름 |
Body/Large | .bodyLarge | 15 | 400 | 150% | −1% | 본문 | 같은 이름 |
Body/Medium | .bodyMedium | 14 | 400 | 150% | −1% | 본문 | 같은 이름 |
Body/Small | .bodySmall | 13 | 400 | 150% | −1% | 본문 | 같은 이름 |
Body/XS | .bodyXs (v2부터) | 12 | 400 | 150% | −1% | 본문 | .bodySmall |
Label/XL2 | .labelXl2 | 16 | 500 | 140% | −1% | 본문 | 같은 이름 |
Label/XL | .labelXl | 15 | 500 | 140% | −1% | 본문 | 같은 이름 |
Label/Large | .labelLarge | 14 | 500 | 140% | −1% | 본문 | 같은 이름 |
Label/Medium | .labelMedium | 13 | 500 | 140% | −1% | 본문 | 같은 이름 |
Label/Small | .labelSmall | 12 | 500 | 140% | −1% | 본문 | 같은 이름 |
Label/XS | .labelXs (v2부터) | 11 | 500 | 140% | −1% | 본문 | .labelSmall |
Code/XS | .codeXs (v2부터) | 11 | 400 | 21px 고정 | 0 | mono | .bodySmall.mono |
Code/SM | .codeSm (v2부터) | 12 | 400 | 21px 고정 | 0 | mono | .bodySmall.mono |
Code/MD | .codeMd (v2부터) | 13 | 400 | 21px 고정 | 0 | mono | .bodySmall.mono |
v2 이전— v2(coui_flutter 0.163 · coui_core 0.162) 전 릴리스에서 같은 자리에 쓰는 체인. 이름이 같아도 값은 대부분 v2 에서 바뀌었다 — 본문이 한 단계 작아지고(bodyMedium16 → 14), 헤드라인이 700 이 되고, 타이틀 · 라벨 행간이 140% 가 됐다. 그 전 릴리스의 값은 그 릴리스의CoreTypography.coui가 정한다 — 이 표의 숫자를 옮겨 쓰지 않는다.
Output Template#
Widget File#
import 'package:core/core.dart';
/// {component_name} widget
///
/// Figma: {figma_node_link}
class {ComponentName} extends StatelessWidget {
const {ComponentName}({
required this.title,
this.onTap,
super.key,
});
final String title;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
// CoUI bare 위젯으로 구성 (Button / Badge / Card / Gap / Icon — v0.127, no Co prefix)
return Button(
onPressed: onTap,
child: Text(title), // Button 이 라벨 역할을 입힌다 — 따로 스타일하지 않는다
);
}
}
Widgetbook UseCase#
@UseCase(name: 'Default', type: {ComponentName})
Widget buildDefault(BuildContext context) {
return const {ComponentName}(
title: 'Sample Title',
);
}
MCP Integration#
| Phase | MCP Server | Tool |
|---|---|---|
| Figma analysis | figma (official Figma MCP) | whoami, create_session, get_design_context, get_variable_defs, get_screenshot |
| Code search | serena | find_symbol, search_for_pattern |
Figma 를 읽지 못하면(whoami · get_design_context 실패) 코드를 만들지 않는다 — 노드 이름이나 스크린샷에서 짐작하지 않는다. get_design_context 의 참조 코드는 React/HTML 이라 Flutter 로 옮겨 적지 않고, figma-to-coui 규칙으로 CoUI 위젯을 고른다.
Core Rules#
Widget Structure#
- Prefer
constconstructor super.keyalways last parameter- Break into small reusable units
Styling#
- No hardcoded colors -> use
context.theme.colorScheme.*/context.appColors.* - Typography ->
context.textStyles.<size><weight>(noText().lg.boldchaining) - Spacing ->
Gap.spaceN()/Gap(gapStyle: CoreGapStyle(...))(noCoGap, noGap.s*/Spacing.s*/Insets.*/Gap(size: CoreSpace.spaceN)v0.92) withOpacity()prohibited -> usewithValues(alpha:)- No magic numbers -> use design tokens (
CoreSpace)
Responsive#
- Utilize
LayoutBuilderorMediaQuery - Minimum touch target 48x48
Examples#
Button Component Creation#
/cc-flutter:ui button --name SubmitButton --feature commonFigma Card Conversion#
/cc-flutter:ui card --figma-node "https://www.figma.com/design/<key>/<name>?node-id=12-345" --name ProductCard --feature storeFull Page Conversion#
/cc-flutter:ui page --figma-node "https://www.figma.com/design/<key>/<name>?node-id=1-100" --name HomePage --feature homeReferences#
- Detailed implementation:
.claude/agents/flutter:ui.md - CoUI components:
package/coui/ - Color system:
package/resources/lib/src/core/theme/