본문으로 건너뛰기

Claude Code 스킬로 Figma-to-Code 퍼블리싱 파이프라인 만들기

·14 min read

개요

Figma 디자인 시안을 Next.js 코드로 변환하는 작업을 Claude Code 스킬 시스템으로 자동화한 경험을 정리한다. 단순한 단일 스킬이 아니라, 오케스트레이터 → 실행 스킬 → 서브에이전트 구조로 설계하여 대형 디자인도 컨텍스트 오버플로우 없이 처리할 수 있도록 했다.

왜 스킬을 만들었나

Figma → 코드 퍼블리싱은 반복적이면서도 실수가 잦은 작업이다:

  • 토큰 매핑을 추측하면 100% 틀린다 (grey.6 vs grey.7)
  • 아이콘을 수동 다운로드하면 currentColor 치환을 빼먹는다
  • 대형 시안을 한 번에 처리하면 컨텍스트가 넘쳐서 뒤쪽 섹션을 추측한다
  • QA를 빼먹으면 strokeDashes(dashed/solid) 같은 세부사항이 누락된다

이런 실수를 구조적으로 방지하려면, 절차를 스킬로 코드화하고 강제하는 게 맞다.

스킬 아키텍처

3계층 구조

┌─────────────────────────────────────────────┐
오케스트레이터 (사용자가 직접 호출)              │
│  figma-to-code-tailwind, publish-qa 등        │
│  → 다른 스킬을 순차 호출, /tmp 캐싱 관리         │
├─────────────────────────────────────────────┤
│  실행 스킬 (오케스트레이터가 호출)               │
│  figma-fetch, figma-publish-tailwind 등       │
│  → 실제 작업 수행 (API 호출, 코드 생성)          │
├─────────────────────────────────────────────┤
│  초기 세팅 스킬 (프로젝트 시작 시 1회)           │
│  token-to-tailwind, token-to-chakra           │
│  → 토큰 변환, 독립 실행                        │
└─────────────────────────────────────────────┘

전체 스킬 맵 (16개)

분류스킬역할
오케스트레이터figma-to-code-tailwind단일 시안 → Tailwind 퍼블리싱
figma-to-code-chakra단일 시안 → ChakraUI 퍼블리싱
responsive-publish-tailwind반응형 → Tailwind 퍼블리싱
responsive-publish-chakra반응형 → ChakraUI 퍼블리싱
publish-qa품질 검증 (commit 전)
실행: 분석figma-fetchFigma REST API 노드 분석 + 스펙 구조화
실행: 자산figma-icons아이콘 SVG 추출
figma-images이미지 추출 (1x/2x)
실행: 구현figma-publish-tailwindTailwind + shadcn/ui 코드 구현
figma-publish-chakraChakraUI 코드 구현
실행: QAdesign-qaFigma ↔ 코드 정밀 대조
publish-refactor프로젝트 컨벤션 리팩토링
edge-case-test훅/유틸 엣지케이스 검증
a11y-seo접근성 + SEO 검사
초기 세팅token-to-tailwindtoken.json → Tailwind config
token-to-chakratoken.json → Chakra 테마

핵심 설계 결정

1. 서브에이전트 위임으로 컨텍스트 오버플로우 방지

문제: 대형 Figma 시안(섹션 8개+)을 메인 컨텍스트에서 처리하면, 뒤쪽 섹션에서 앞쪽 스펙을 "까먹고" 추측하기 시작한다.

해결: 오케스트레이터는 직접 구현하지 않고, 서브에이전트에 위임한다. 각 에이전트는 독립 컨텍스트를 가지므로 오버플로우가 발생하지 않는다.

오케스트레이터 (메인 컨텍스트)
├── PHASE 0: figma-fetch → /tmp/figma-spec-cache.md 저장
├── PHASE 1: figma-icons, figma-images
├── PHASE 1.5: 섹션 분할 → /tmp/figma-spec-section-*.md
└── PHASE 2: 섹션별 서브에이전트 spawn (독립 컨텍스트)
    ├── Agent 1: Header 섹션 (자기 스펙만 로드)
    ├── Agent 2: Content 섹션
    └── Agent 3: Footer 섹션

각 에이전트의 컨텍스트 배분:

[공유 컨텍스트 ~15%] + [섹션 스펙 ~15%] + [스킬 규칙 ~20%] + [구현 ~50%]
= 충분한 여유

2. /tmp 캐싱으로 API 재호출 방지

Figma REST API 호출은 비용이 크다. PHASE 간 데이터를 /tmp에 저장하여 재사용한다.

# PHASE 0에서 저장
/tmp/figma-spec-cache.md        # 전체 디자인 스펙
 
# PHASE 1.5에서 분할
/tmp/figma-spec-shared.md       # 공유 컨텍스트 (토큰, 자산, 구조)
/tmp/figma-spec-section-1-header.md
/tmp/figma-spec-section-2-content.md
/tmp/figma-spec-section-3-footer.md
 
# publish-qa에서 저장
/tmp/publish-qa-step1.md        # 디자인 QA 결과
/tmp/publish-qa-step2.md        # 리팩토링 결과
/tmp/publish-qa-step3.md        # 엣지케이스 결과

PRE/POST에서 캐시를 정리하여 이전 세션 오염을 방지한다:

# PRE: 작업 시작 전
rm -f /tmp/figma-spec-cache.md /tmp/figma-spec-section-*.md
 
# POST: 작업 완료 후
rm -f /tmp/figma-spec-cache.md /tmp/figma-spec-section-*.md

3. 섹션 분할 전략 (대형 디자인 대응)

디자인 규모루트 직계 자식 수전략
소형1~3개단일 에이전트
중형4~7개2~3개 그룹 분할
대형8개+섹션별 개별 에이전트

병렬 spawn은 파일 충돌 위험이 있으므로, 섹션 에이전트는 순차 실행한다.

4. publish-qa도 서브에이전트 기반

처음에는 publish-qa가 메인 컨텍스트에서 4개 STEP을 모두 실행했다. 하지만 design-qa(Figma API + 토큰 역색인 + 대조 테이블)와 publish-refactor(12개 검사 항목 + 반복 수정)가 각각 무거워서 컨텍스트가 부족했다.

Before: 메인에서 모두 실행 → 뒤쪽 STEP에서 품질 저하

After: STEP별 독립 서브에이전트 + /tmp 리포트 캐싱

publish-qa (오케스트레이터)
├── PRE: /tmp/publish-qa-step*.md 캐시 정리
├── STEP 1: 서브에이전트 → /design-qa       → /tmp/publish-qa-step1.md
├── STEP 2: 서브에이전트 → /publish-refactor → /tmp/publish-qa-step2.md
├── STEP 3: 서브에이전트 → /edge-case-test   → /tmp/publish-qa-step3.md (조건부)
├── STEP 4: 메인 → pnpm build (가벼움)
└── POST: 캐시 정리 + 최종 보고

STEP 4(빌드 체크)만 메인에서 실행하는 이유: pnpm build는 가벼운 명령이고, 에러 발생 시 즉시 수정해야 하므로 메인 컨텍스트가 적합하다.

오케스트레이터 워크플로우 상세

figma-to-code-tailwind (단일 시안 퍼블리싱)

PRE:     /tmp 캐시 정리
PHASE 0: /figma-fetch → 노드 분석 + 스펙 → /tmp/figma-spec-cache.md
PHASE 1: /figma-icons, /figma-images → 자산 처리 (조건부)
PHASE 1.5: 섹션 분할 판단
PHASE 2: 서브에이전트 → /figma-publish-tailwind
PHASE 3: 통합 검증 (페이지 조립 + type-check)
POST:    캐시 정리

ChakraUI 버전(figma-to-code-chakra)에는 **PHASE 0.5(MCP 힌트 검증)**이 추가로 있다. MCP get_design_context가 반환하는 Tailwind 근사값을 REST API로 교차 검증하는 단계다.

responsive-publish-tailwind (반응형 퍼블리싱)

단일 서브에이전트에 전체 위임:
  STEP 0: URL 파싱 + 프로젝트 구조 확인
  STEP 1: 브레이크포인트별 get_design_context 개별 조회
  STEP 2: 섹션별 브레이크포인트 차이 비교 테이블
  STEP 3: 토큰 역색인 빌드
  STEP 4: 자산 처리
  STEP 5: 반응형 구현 설계서
  STEP 6: Tailwind 반응형 코드 구현 (md:, lg: 접두사)
  STEP 7: pnpm type-check

입력 형식:

/responsive-publish-tailwind <설명> URL([base, md|null, lg|null]) --page src/app/path

핵심: 각 브레이크포인트 URL을 개별 조회한다. 하나만 조회하고 나머지를 추측하면 반응형 차이점을 놓친다.

토큰 매핑: 추측을 구조적으로 차단

퍼블리싱에서 가장 흔한 실수는 토큰 추측이다.

"grey.6 정도 되겠지" → 실제는 grey.7
"pre-body-3이겠지" → 실제는 pre-heading-5 (16px/700은 heading)
"border-grey-3이겠지" → 실제는 border.basic.2 (같은 hex라도 컨텍스트가 다름)

역색인 빌드 (추측 차단의 핵심)

token.json에서 3가지 역색인을 빌드하면, Figma 노드 데이터에서 정확한 토큰 이름을 자동 resolve할 수 있다.

// 1. VariableID → 시맨틱 토큰 (색상)
semanticById["VariableID:4021:1253"] = { token: "border-basic-2", value: "#cfd2d5" }
 
// 2. VariableID → 원시 색상
rawById["VariableID:100:50"] = { name: "grey-50", value: "#f9f9fa" }
 
// 3. fontSize/fontWeight → textStyle 토큰
textStyleIndex["14/600"] = "pre-body-5"
textStyleIndex["24/700"] = "pre-heading-2"

매핑 우선순위:

  1. boundVariables VariableID → 역색인 (정확도 100%)
  2. hex + CSS 컨텍스트 폴백 (같은 hex라도 stroke vs fill로 다른 토큰)
  3. 프로젝트 토큰 파일 역방향 조회 (최후 수단)

초기 세팅: token-to-tailwind / token-to-chakra

이 스킬들은 오케스트레이터 플로우에 포함되지 않는 독립 실행 스킬이다. 프로젝트 초기에 한 번 실행하면 토큰이 세팅되고, 이후 퍼블리싱 스킬들은 세팅된 토큰을 참조만 한다.

Tailwind 변환 흐름

token.json → CSS Variables (globals.css) + tailwind.config.ts 확장
/* globals.css */
:root {
  --color-grey-50: #f9f9fa;
  --color-accent-yellow1: #fef2e3;
}
.dark {
  --color-accent-yellow1: #322304;
}
// tailwind.config.ts
colors: {
  grey: { 50: 'var(--color-grey-50)' },
  accent: { yellow1: 'var(--color-accent-yellow1)' },
}

Chakra 변환 흐름

token.json → Chakra theme 객체 (colors, semanticTokens, textStyles)

v2와 v3의 차이:

v3 (createSystem)v2 (extendTheme)
색상{ value: '#hex' } 래퍼'#hex' 직접
시맨틱{ _light, _dark }{ default, _dark }
textStyle{ value: { ... } } 래퍼래퍼 없이 직접

.claude/skills/ vs .claude/agents/ 차이

스킬을 정리하면서 skills/agents/로 분리하려 했으나, Claude Code에서 이 둘은 동작이 다르다:

  • .claude/skills//slash-command로 호출 가능
  • .claude/agents/Task({ subagent_type: "name" })으로만 호출 가능

현재 오케스트레이터들이 서브에이전트 안에서 /figma-publish-tailwind 등을 슬래시 커맨드로 호출하고 있어서, 실행 스킬을 agents/로 옮기면 호출이 깨진다. 따라서 모두 skills/에 유지하고, README에서 카테고리를 분류하는 방식을 택했다.

프로젝트 간 이식

다른 프로젝트에 스킬을 복사할 때 수정해야 하는 부분:

항목현재 값수정 대상
token.json 경로apps/admin/public/token.json프로젝트 실제 경로
FIGMA_TOKEN 위치apps/admin/.env.local프로젝트 실제 경로
컴포넌트 디렉토리apps/admin/src/components/프로젝트 실제 경로
아이콘 생성 명령pnpm tokript gen:icon프로젝트 실제 명령
type-check 명령pnpm type-check프로젝트 실제 명령

UI 프레임워크에 따라 사용하는 스킬 세트가 다르다:

스택퍼블리싱반응형토큰 세팅
Tailwind + shadcn/uifigma-to-code-tailwindresponsive-publish-tailwindtoken-to-tailwind
ChakraUIfigma-to-code-chakraresponsive-publish-chakratoken-to-chakra

공통 스킬(figma-fetch, figma-icons, figma-images, publish-qa, a11y-seo)은 프레임워크 무관하게 사용 가능하다.

배운 것

  1. 컨텍스트 윈도우는 유한하다. 무거운 작업을 메인에서 전부 돌리면 뒤쪽에서 품질이 떨어진다. 서브에이전트 위임이 답이다.

  2. 추측은 구조적으로 차단해야 한다. "토큰을 추측하지 마라"는 규칙만으로는 부족하다. 역색인 빌드를 강제하고, 매핑 근거를 테이블에 기재하게 해야 실제로 추측이 사라진다.

  3. 캐싱은 PHASE 간 다리다. 서브에이전트는 메인 컨텍스트를 공유하지 않으므로, /tmp 파일이 유일한 데이터 전달 수단이다. PRE/POST 정리까지 포함해야 오염을 방지한다.

  4. 스킬 분리의 기준은 "컨텍스트 무게"다. 가벼운 작업(pnpm build)은 메인에서, 무거운 작업(디자인 QA, 리팩토링)은 서브에이전트에서 실행한다.

  5. skills/ vs agents/ 구분을 이해해야 한다. Claude Code에서 이 둘은 호출 방식이 다르다. 오케스트레이터가 슬래시 커맨드로 실행 스킬을 호출하는 구조라면, 실행 스킬도 skills/에 있어야 한다.