binlog
Projects/DesignFlow AI Builder

DesignFlow AI Builder

Figma 디자인 구조를 분석해 컴포넌트를 식별하고, React + Tailwind 코드로 자동 변환하는 AI 기반 코드 생성 시스템. 디자인 토큰 추출부터 LLM 기반 구조 해석, 코드 생성까지 하나의 파이프라인으로 연결했습니다.

RoleAI 백엔드 개발, 풀스택Year2026
Next.js 15TypeScriptTailwind CSS v4PythonFastAPIOllamaClaude APIPostgreSQL
DesignFlow AI Builder
01

Problem

Figma로 완성된 디자인을 코드로 옮기는 과정에서, 개발자는 어떤 요소가 컴포넌트인지를 직접 판단해야 합니다. 동일한 디자인이라도 개발자마다 컴포넌트 경계를 다르게 해석하고, 색상·폰트·간격 같은 디자인 토큰을 코드 변수로 변환하는 작업도 매번 수동으로 이루어집니다. Figma는 CSS 수치를 제공하지만 실제 React 컴포넌트 구조는 제공하지 않아, 디자인-개발 사이의 간격을 메우는 과정에 반복적인 수작업이 발생합니다.

02

Limitation

기존 디자인-to-코드 도구들은 마크업 수준의 CSS 변환에 그치며, 컴포넌트 단위의 구조나 재사용 가능한 설계를 자동으로 추론하지 못합니다. 또한 색상, 타이포그래피, 간격이 각각 분리된 형태로 존재해 하나의 디자인 시스템으로 통합하고 Tailwind 클래스로 매핑하는 과정이 체계화되어 있지 않습니다. Figma 노드 트리 분석, 토큰 추출, 컴포넌트 식별, 코드 생성이 각각 분리되어 있어 이를 하나의 자동화된 흐름으로 연결하는 시스템이 부족합니다.

03

Solution

DesignFlow는 Figma JSON을 입력으로 받아 React + Tailwind 코드를 출력하는 과정을 파싱 → 정규화 → 토큰 추출 → AI 해석 → 코드 생성의 4단계 파이프라인으로 설계했습니다. Figma 노드 트리를 재귀 순회해 레이아웃 의도와 반복 패턴을 추론하고, 색상·타이포그래피·간격·반경 값을 사용 빈도 기준으로 정규화해 Tailwind 유틸리티 클래스로 매핑했습니다. LLM(Ollama 또는 Claude)을 3단계로 분리해 호출하도록 설계해, 각 단계에 필요한 최소한의 데이터만 전달함으로써 응답 품질과 처리 효율을 함께 확보했습니다.

04

System Architecture

Figma JSON Input
      |
      v
[figma_parser.py] → 노드 트리 파싱
      |
      v
[normalizer.py] → 노드 계층 정규화
      |
      v
[token_extractor.py] → 디자인 토큰 추출
 ├── colors     → Tailwind bg-[#hex]
 ├── typography → text-sm font-bold
 ├── spacing    → p-4 gap-6
 └── radius     → rounded-lg
      |
      v
[Claude / Ollama — 3단계 AI 파이프라인]
 ├── analyze_structure() → componentCandidates + layoutPattern
 ├── name_components()   → suggestedName + filePath
 └── generate_code()     → React + Tailwind TSX
      |
      v
Output Files
 ├── components/HeroSection.tsx
 ├── components/Header.tsx
 └── app/page.tsx
05

Key Implementation

Figma 노드 트리를 재귀 순회해 레이아웃 의도와 반복 패턴을 추론하는 구조 분석 로직을 구현했습니다. 색상·타이포그래피·간격·반경 값을 사용 빈도 기준으로 정규화하고, px 값을 Tailwind 유틸리티 클래스로 변환하는 토큰 매핑 로직을 외부 라이브러리 없이 직접 구현했습니다. LLM을 3단계(구조 분석 → 컴포넌트 명명 → 코드 생성)로 분리해 호출하고, 각 단계는 전체 Figma JSON이 아닌 해당 단계에 필요한 데이터만 전달받도록 설계했습니다. 분석 실행을 백그라운드 태스크로 처리하고 클라이언트에서 폴링하는 구조를 적용해 응답 대기 중에도 UI가 블로킹되지 않도록 구성했습니다.

06

Key Code

01run_pipeline — 6-Stage Async Pipelinepython
1async def run_pipeline(db: AsyncSession, analysis_id: uuid.UUID) -> None:
2 """Figma JSON을 React + Tailwind 코드로 변환하는 6단계 파이프라인."""
3 run = await db.get(AnalysisRun, analysis_id)
4 run.status = AnalysisStatus.running
5 run.started_at = datetime.now(timezone.utc)
6 await db.flush()
7
8 try:
9 raw_json = run.raw_input or {}
10
11 # Stage 1: Figma JSON → 내부 노드 트리
12 parsed = parse_figma_json(raw_json)
13
14 # Stage 2: 노드 계층 정규화 (중복 제거, 깊이 평탄화)
15 normalized = normalize_tree(parsed)
16 run.normalized_tree = normalized
17
18 # Stage 3: 디자인 토큰 추출 (색상, 타이포그래피, 간격, 반경)
19 tokens = extract_tokens(normalized)
20 run.design_tokens = tokens
21
22 # Stage 4: LLM — 컴포넌트 후보 구조 분석
23 analysis_result = await analyze_structure(normalized, tokens)
24 candidates = analysis_result.get("componentCandidates", [])
25
26 # Stage 5: LLM — 컴포넌트 의미적 명명
27 named_result = await name_components(candidates)
28 named_candidates = named_result.get("componentCandidates", candidates)
29 run.ai_interpretation = {**analysis_result, "componentCandidates": named_candidates}
30
31 # Stage 6: LLM — React + Tailwind TSX 코드 생성
32 code_result = await generate_code(named_candidates, tokens)
33 run.generated_code = code_result
34 run.status = AnalysisStatus.completed
35 run.ai_model_used = "claude-sonnet-4-6"
36
37 except InvalidFigmaJsonException as e:
38 run.status, run.error_message = AnalysisStatus.failed, str(e)
39 except Exception as e:
40 logger.error("파이프라인 실패: %s", e, exc_info=True)
41 run.status, run.error_message = AnalysisStatus.failed, "내부 오류: " + str(e)
42
43 run.completed_at = datetime.now(timezone.utc)
44 await db.flush()

Figma JSON을 파싱 → 정규화 → 토큰 추출 → AI 구조 분석 → AI 컴포넌트 명명 → 코드 생성의 6단계로 처리합니다. 각 LLM 단계에 필요한 데이터만 전달해 응답 품질과 처리 효율을 함께 확보합니다.

02run_analysis — Background Task Dispatchpython
1@router.post("", response_model=AnalysisRunCreated, status_code=202)
2async def run_analysis(
3 data: AnalysisRunRequest,
4 background_tasks: BackgroundTasks,
5 db: AsyncSession = Depends(get_db),
6):
7 try:
8 created = await analysis_service.create_analysis(db, data.project_id, data.figma_json)
9 await db.commit()
10 # 파이프라인을 백그라운드로 실행 — 클라이언트는 폴링으로 상태 확인
11 background_tasks.add_task(_run_pipeline_bg, created.id)
12 return created
13 except ProjectNotFoundException:
14 raise HTTPException(status_code=404, detail={"error": {"code": "NOT_FOUND"}})
15 except InvalidFigmaJsonException as e:
16 raise HTTPException(status_code=422, detail={"error": {"code": "INVALID_FIGMA_JSON", "message": str(e)}})
17
18@router.get("/{analysis_id}/status", response_model=AnalysisStatusResponse)
19async def get_status(analysis_id: uuid.UUID, db: AsyncSession = Depends(get_db)):
20 try:
21 return await analysis_service.get_analysis_status(db, analysis_id)
22 except AnalysisNotFoundException:
23 raise HTTPException(status_code=404, detail={"error": {"code": "NOT_FOUND"}})

분석 요청을 202로 즉시 수락하고 파이프라인을 백그라운드 태스크로 실행합니다. 클라이언트는 /status 엔드포인트를 폴링해 완료 여부를 확인하므로, 긴 처리 중에도 UI가 블로킹되지 않습니다.

07

Result & Learnings

Figma 노드 구조를 컴포넌트 단위로 해석하는 과정에서, LLM을 단순 코드 생성기가 아니라 디자인 의도를 추론하는 해석 엔진으로 활용할 수 있음을 확인했습니다. 각 LLM 호출 단계에 전체 JSON이 아닌 필요한 데이터만 전달하는 방식이 응답 품질과 파싱 안정성을 함께 높이는 데 효과적이었습니다. 또한 Auto Layout, Component Sets, Variants 같은 고급 Figma 기능은 단순 노드 트리 분석으로 완전히 처리하기 어렵다는 한계를 확인했고, 이를 처리하기 위해서는 Figma 플러그인 API 수준의 접근이 필요하다는 점을 파악했습니다.

Links