Case Study · Design System Infra

Figma에서 코드까지 —
디자인 시스템 자동화 파이프라인

디자이너가 토큰을 바꾸면 슬랙으로 전달받아 손으로 옮겨 적었고, 빠뜨린 건 QA에서 발견됐습니다.
"이걸 왜 사람이 하지?"가 시작이었습니다.

Figma를 SSOT로 두는 파이프라인을 만들고,
그 위에 신규 디자인 시스템을 구축해 전사 웹 프로덕트에 적용 중입니다.

자비스앤빌런즈(삼쩜삼) · FE 3인 팀 · 파이프라인 설계·구현 주도 (기여도 80%) · 디자이너와 토큰 컨벤션 공동 정의

571개 ×2Light/Dark CSS 변수 자동 빌드validator가 CI에서 강제
65종컴포넌트 스펙 JSON 자동 추출variant·슬롯 스타일 포함
51종Figma Code Connect 매핑디자이너 화면에 실제 코드 노출
8개 앱전사 웹 프로덕트 실사용 중최대 채택 앱: 42개 파일 · 20종
01 · Problem

모든 변경이 사람 손을 거쳤습니다

Before

🎨
디자이너 #design-update
버튼 색 바꿨어요! 반영 부탁드려요 🙏
Figma 슬랙 사람 눈 코드

⚠ 어디까지 반영됐는지 아무도 모름

After

$ pnpm figma:pull && pnpm build
 571 tokens → CSS / Tailwind
 validator 571/571
Figma CLI 코드

누락이 있으면 QA가 아니라 빌드가 알려줍니다

02 · Architecture

값의 파이프라인, 구조의 파이프라인

① Figma — 디자이너
surface-primary
변수 값 변경
figma:pull
② 토큰 JSON
"surface-primary":
  { "value": "#15b077" }
build
③ 빌드된 CSS
--surface-primary: #15b077;
--button-surface: var(--surface-primary); ← 수정 없음
✓ validator 571/571
배포
④ 프로덕트
코드 수정 0줄
같은 이름 surface-primary가 Figma 변수 → JSON → CSS 변수 → 컴포넌트까지 네 계층을 그대로 관통합니다 — 번역 과정이 없으니 어긋날 곳도 없습니다.
Source of Truth

Figma

Variables(토큰 컬렉션 4계층) + ComponentSet(컴포넌트 정의)

Variables API  ·  REST API
Pipeline A — 값

디자인 토큰 자동 빌드

surface-primary LightDark
figma:pull → build  ↓
:root { --surface-primary: #15b077 }
.dark { --surface-primary: #0e8a5f }

CSS 변수 571개 ×2 모드 + Tailwind v4 @theme — 누락은 validator가 빌드 실패로 차단

Pipeline B — 구조

컴포넌트 스펙 자동 추출

Button variant=primary · size=large
figma:extract  ↓
"variant=primary, size=large, …": {
  "base": { "fill": "$surface-primary" }
}

variant·슬롯별 스타일을 담은 스펙 JSON 65종 — 구현의 단일 참조점

npm 패키지로 버저닝·배포 → 이를 기반으로 신규 디자인 시스템 구현 (tailwind-variants · React 19)
→ 구현하는 사람·AI

Code Connect 51종 + Claude Code 스킬

Figma Dev ModeClaude Code
시안 선택 · "만들어줘"  ↓
<Button variant="primary" size="large">

시안을 raw CSS/div로 다시 만들지 않도록, 사람에게도 AI에게도 실제 컴포넌트 코드를 바로 제공

03 · Pipeline A — Tokens & Theming

시맨틱 토큰 54개만 덮어쓰면 브랜드가 바뀝니다

버튼 색은 #15b077 같은 값이 아니라 "시맨틱 토큰을 따라간다"로 저장돼 있습니다 (var() 참조).
그래서 시맨틱 토큰 54개만 갈아끼우면 그걸 따라가는 모든 컴포넌트가 함께 바뀝니다. 직접 눌러보세요.

실제 컴포넌트 구동 중 — 빌드된 디자인 시스템 컴포넌트 + 토큰 CSS 번들 · 인증 서비스 '정보 입력' 화면 구성
실제 컴포넌트입니다 — 직접 입력해보세요.
주민번호 마스킹 · 클리어 버튼 · error 상태까지 서비스와 동일하게 동작합니다.
Brand를 전환해도 바뀌는 건 시맨틱 토큰 값뿐 — 컴포넌트 코드는 수정되지 않습니다.
/* 빌드 산출물 — 컴포넌트 토큰은 참조를 보존한다 */
:root { --surface-primary: #15b077; }
[data-theme="brand-b"] { --surface-primary: #d97a06; }  /* 시맨틱 54개만 오버라이드 */

--primary-enabled-button-surface: var(--surface-primary);  /* hex로 굳히지 않음 → 브랜드가 바뀌면 따라감 */
04 · Pipeline B — Spec Extraction

Figma를 열어 옮겨 적는 일을 없앴습니다

버튼 하나의 상태 조합이 120개(variant 5 × 형태 2 × 크기 4 × 상태 3) — 이걸 하나씩 클릭해 옮겨 적는 게 구현에서 가장 오래 걸리는 일이었습니다.

Before — 점 하나가 조합 하나. 120번 클릭해서 눈으로 옮겨 적기
// After — 명령 한 번으로 생성되는 spec.json
"size=small, state=enabled,
 value=selected": {
  "switch-track": {
    "fill": "$surface-primary",
    "cornerRadius": 999
  },
  "switch-thumb": {
    "fill": "$icon-basic-inverse"
  }
}
After — 120개 조합의 스타일이 파일 하나로. 구현할 때 Figma를 열지 않고 이것만 봅니다

디자인이 바뀌면 이 파일의 diff로 드러납니다 — 디자인 변경도 코드처럼 리뷰됩니다. 코드 생성까지는 자동화하지 않았습니다 — 인터페이스·접근성은 스펙만으로 판단할 수 없어, 사람이 결정합니다.

figma:sync — 65종 재동기화 (실제 출력 형식 재구성)
$ pnpm figma:sync
발견된 spec.json 파일: 65개
571개의 디자인 토큰 로드 완료
🔄 Button/spec.json 동기화 중...       ⏭  변경사항 없음
🔄 Switch/spec.json 동기화 중...       ✅ 완료 (스타일 2건 갱신)
🔄 Input/spec.json 동기화 중...        ⏭  변경사항 없음
… 62개 생략 …
동기화 완료: 1개 갱신, 64개 변경 없음, 0개 실패
05 · Deterministic Gates

어기면 빌드가 깨지게 만들었습니다

"잘 지켜달라"는 부탁 대신, 사람·AI·시간이 만드는 드리프트를 각 계층의 검증 게이트가 막습니다.

$ pnpm build
✗ css-validator — missing token: surface-tertiary (570/571)
build failed
게이트지키는 것어기면
토큰 validator소스 토큰 ↔ 생성된 CSS 변수 1:1 (571개 전수 대조)빌드 실패
참조 치환 검사깨진 토큰 참조가 CSS로 새어 나가 조용히 무효화되는 것빌드 실패
자체 ESLint 룰슬롯 오버라이드를 뒤따르는 className이 조용히 덮어쓰는 것 (타입이 못 잡아 lint가 맡음)린트 에러
Code Connect 검사기Figma 속성 rename·옵션 변경으로 51종 매핑이 어긋나는 것exit 1
스킬 문서 검증가이드 문서의 prop·값 ↔ 배포 타입(d.ts) 불일치, 예제 코드 컴파일 실패CI 에러
06 · Code Connect & AI Skill

코드를 소비하는 건 사람 개발자만이 아닙니다

시안을 구현하는 개발자에게 — Code Connect 51종

Dev Mode에서 시안을 클릭했을 때 보이는 코드를 바꿉니다.

Figma Dev Mode — 시안에서 Button 선택
Code Connect 없이
display: flex;
padding: 13px 20px;
background: #15b077;
border-radius: 12px; …

CSS 덩어리를 보고 raw CSS로 재구현 → 시스템 우회

Code Connect 매핑 후
<Button variant="primary" size="large">
  환급액 조회하기
</Button>

이 코드를 그대로 복사해 쓰면 됩니다

매핑 초안은 스크립트가 생성하고 판단만 사람이 검토 — Figma 속성이 바뀌어 어긋나면 자체 드리프트 검사기가 CI에서 차단

시안을 구현하는 AI에게 — Claude Code 스킬

사용 가이드 35편을 스킬로 배포해, AI가 raw div 대신 시스템 컴포넌트로 구현하게 합니다.

Claude Code — 사내 디자인 시스템 스킬 활성화됨
개발자
이 시안대로 버튼 만들어줘
AI
시스템 컴포넌트로 구현합니다
<Button variant="primary" size="large">
개발자
여기에 캘린더도 넣어줘
AI
캘린더는 시스템에 없는 컴포넌트예요 — 임의로 만들지 않고 확인을 요청합니다

가이드의 prop·예제 코드는 배포 타입 정의(d.ts) 기준으로 자동 검증됩니다

07 · Adoption

만드는 것보다 채택되는 것이 임팩트

전사 웹 앱 18개 중 8개가 실사용 중입니다.

앱별 시스템 컴포넌트 import 파일 수 (2026-09 기준) · 사용 컴포넌트 최다 앱은 22종 사용