트렌딩 딥다이브 · 2026-07-18 · OSSInsight #12 · TrendShift Monthly #17

microsoft/flint-chart 딥다이브
— 열 줄짜리 "차트 설계도"로 Vega-Lite·ECharts·Chart.js를 한 번에 뽑는 시각화 컴파일러

Flint"이 데이터 열이 무슨 의미인가(가격·연월·순위·상관계수…)"와 "무슨 차트를 원하는가"만 선언하면, 축·눈금·0 기준선·집계·숫자/날짜 포맷·색상·범례·간격 같은 저수준 설정을 데이터에서 자동으로 유도해 주는 시각화 중간언어(IL) + 컴파일러다. 마이크로소프트 리서치가 만든 오픈소스로, 똑같은 입력 하나로 Vega-Lite·ECharts·Chart.js 세 가지 네이티브 스펙을 모두 생성한다. 먼저 오해를 풀자 — 이건 또 하나의 차트 라이브러리가 아니다. 기존 차트 라이브러리들 "위에" 앉아 그것들을 타깃으로 코드를 뽑아내는 상위 계층 컴파일러다. 두 번째로 각인할 것 — 이 프로젝트의 진짜 노림수는 "AI 에이전트가 신뢰성 있게 차트를 그리게" 하는 것이다. 그래서 MCP 서버에이전트 스킬이 1급으로 딸려 온다. 이 문서는 소스를 직접 클론해 "이 저장소에서 무엇을 배울 수 있는가"를 파고든다. (저장소: microsoft/flint-chart · TypeScript 모노레포 · MIT © Microsoft · Microsoft Research × 런민대 IDEAS Lab · npm flint-chart/flint-chart-mcp v0.2.2(2026-07-15) · 최신 커밋 2026-07-17 · 별 1,854 · 이번 회차는 TrendShift Daily·Weekly·Monthly가 모두 기분석 소진되어 OSSInsight 순위로 폴백)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 지금 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트
  7. 시스템 요구사항 · 설치
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

"데이터의 의미 + 원하는 차트"만 선언 → 나머지 디자인은 컴파일러가 — Vega-Lite·ECharts·Chart.js를 하나의 입력에서

microsoft/flint-chart(줄여서 Flint)는 차트를 "어떻게 그릴지" 일일이 지정하는 대신, "데이터가 무엇을 뜻하는지"와 "어떤 차트인지"만 짧게 선언하면 되도록 만든 오픈소스 시각화 도구다. 저장소가 내건 한 줄은 이것 — "Flint is a visualization language that lets AI agents reliably create expressive, good-looking charts from simple, human-editable chart specs."(AI 에이전트가 간단하고 사람이 편집 가능한 차트 스펙으로부터 표현력 있고 보기 좋은 차트를 안정적으로 만들게 해 주는 시각화 언어).

핵심은 두 개의 선언을 나눠 준다는 것이다. ① semantic_types — 각 데이터 열이 무슨 의미인지(예: price는 "금액", 202401은 "연월", rank는 "순위"). ② chart_spec — 어떤 차트 타입에 어떤 열을 어느 채널(x·y·color·size…)에 꽂을지. 대개 10줄 안팎이다. 그러면 Flint 컴파일러가 스케일·축·0 기준선·집계 방식·통화/퍼센트/날짜 포맷·색상 스킴·범례·여백·facet 격자·종횡비까지 전부 데이터 + 의미 + 차트타입으로부터 유도해, Vega-Lite / ECharts / Chart.js 각각의 완성된 네이티브 스펙을 뽑아낸다.

핵심 용어 · 이게 뭐냐
Flint = "시각화 중간언어(IL) + 컴파일러"
중간언어(Intermediate Language)는 컴파일러가 소스코드와 최종 기계어 사이에 두는 중간 표현이다. Flint에서 "소스코드"는 짧은 차트 스펙, "기계어"는 Vega-Lite·ECharts·Chart.js 같은 실제 렌더링 라이브러리의 스펙이다. 즉 Flint는 차트 라이브러리를 "실행 타깃"으로 삼는 상위 언어이고, 우리가 짧게 쓴 스펙을 각 타깃의 장황한 설정으로 "컴파일"해 준다.
핵심 용어 · Flint의 심장
시맨틱 타입(Semantic Type) — "저장 타입"이 아니라 "의미 타입"
보통 차트 도구는 열을 저장 타입(숫자/문자열/날짜)으로만 본다. 그래서 202401을 그냥 큰 숫자로 그려 버린다. Flint은 여기에 의미 타입 레이어를 얹는다 — YearMonth(연월)라고 말해 주면 시간 축으로, Price면 통화 포맷 + 0 기준선으로, Correlation이면 [-1, 1] 고정 발산형 색상으로, Rank면 축을 뒤집어(1위가 위로) 그린다. "의미"가 디자인을 결정한다.
한 문장 비유

"재료의 '성격'만 알려 주면 접시까지 알아서 차려 주는 주방장"

직접 Vega-Lite/ECharts 스펙을 쓰는 건 요리의 불 세기·간·플레이팅을 한 줄씩 다 지시하는 것과 같다. 한 번은 되지만, 재료(필드)를 바꾸거나 접시(차트 타입)를 바꾸면 지시서 전체가 무너진다.

Flint에게는 "이건 가격, 이건 연월, 이건 순위"라고 재료의 성격만 말하면 된다. 주방장(컴파일러)이 "가격이면 원화 표기에 0부터", "순위면 1등을 맨 위로" 같은 요리 규칙을 스스로 적용해 완성된 접시를 내온다. 게다가 같은 주문서로 양식·중식·일식(Vega-Lite·ECharts·Chart.js) 어느 주방에서든 똑같이 차려 준다.

2왜 지금 주목받는가

Microsoft Research발(發) · "AI가 차트를 그리는 시대"의 신뢰성 문제를 정조준

Flint이 2개월 만에 별 1,800+를 모으며 트렌딩에 오른 이유는 "또 하나의 차트 라이브러리"여서가 아니다. 기존 선언형 문법(Vega-Lite·ECharts)이 의미와 저장표현이 어긋날 때 취약하다는 오래된 문제와, LLM 에이전트가 장황한 차트 스펙을 안정적으로 못 만든다는 새 문제를 동시에 겨냥했기 때문이다. 제작자는 Microsoft Research런민대(Renmin University) IDEAS Lab이며, 논문도 "coming soon"으로 예고돼 있다.

포인트내용
정체시맨틱 기반 시각화 컴파일러. data + semantic_types + chart_spec을 받아 Vega-Lite·ECharts·Chart.js 네이티브 스펙을 생성. 30+ 통계 차트 타입, 70개 안팎의 시맨틱 타입.
차별점 ①시맨틱 타입이 1급. 저장 타입(Q/O/N/T)이 아니라 의미(Price·YearMonth·Rank·Correlation…)가 포맷·색상·축 방향을 결정. 3계층 graceful degradation(뒤에서 상술).
차별점 ②물리 기반 auto-layout. 데이터가 캔버스보다 커지면 스프링·가스 압력·원주·면적 모델로 크기를 조절 — 문서에 실제 수식까지(1,110줄).
차별점 ③군론적 Named Views. 축 전치·색↔계열 교환·facet·형제 차트로의 전환을 4개 생성원의 궤도(orbit) + 안정자 몫(stabilizer quotient)으로 열거·중복제거. 추상대수의 실전 적용.
차별점 ④에이전트 통합이 기본. 별도 npm 패키지 flint-chart-mcp(MCP 서버) + 566줄짜리 에이전트 스킬을 제공해, 어떤 MCP 에이전트든 신뢰성 있는 차트 작가로 만든다.
제작자 · 라이선스Microsoft Research × 런민대 IDEAS Lab. 공식 microsoft/ 저장소. MIT 라이선스. 코어 라이브러리는 런타임 의존성 0개.

주목 포인트 1 — "선언형 문법이 의미를 모른다"는 근본 문제

Vega-Lite·ECharts 같은 문법은 저장 타입이 시각 매핑과 맞아떨어질 때는 훌륭하다. 문제는 의미가 저장표현과 어긋날 때 생긴다. 저장소 문서가 든 대표 실패 사례 세 가지 — ① 정수 202001은 사실 연월(시간 밴드)인데 크기 값으로 그려진다. ② 온도·비율처럼 더할 수 없는(non-additive) 측정값을 문법은 아무렇지 않게 스태킹해 버린다. ③ 손익·상관계수처럼 발산형(diverging) 필드를 순차 색상 램프에 잘못 매핑한다. 전문가는 긴 스펙을 손수 짜서 고칠 수 있지만, 필드 하나만 바꿔도 그 스펙이 통째로 깨진다. Flint은 "의미"를 1급으로 올려 이 취약성을 컴파일러가 책임지게 했다.

주목 포인트 2 — LLM 에이전트에게는 문제가 더 크다

에이전트가 차트를 그리려고 완전한 Vega-Lite 스펙을 통째로 생성하면 토큰이 비싸고, 작은 수정에도 스펙 전체를 다시 뱉어야 하며, 틀리기 쉽다. Flint의 접근은 정반대다 — 에이전트는 컴팩트하고 안정적인 프로그램(짧은 스펙)만 내보내고, "정확성"은 컴파일러가 맡는다. 그래서 MCP 서버·에이전트 스킬이 부록이 아니라 설계의 중심에 있다. "AI가 데이터로 차트를 그리는" 워크플로가 폭증하는 지금, 정확히 그 지점의 신뢰성 도구라는 점이 트렌딩의 동력이다.

경쟁 구도 · Flint은 어디에 서 있나

vs Vega-Lite/ECharts/Chart.js 직접 작성 — 그것들은 Flint의 타깃(출력)이다. 10줄을 쓰면 컴파일러가 수백 줄의 네이티브 스펙을 유도한다.

vs matplotlib / 에이전트가 직접 짠 플로팅 코드 — 장황하고 취약하며 매번 재실행이 필요. Flint 스펙은 짧고 선언적이며 백엔드 간 이식 가능.

vs Mermaid — Mermaid는 다이어그램(플로차트·시퀀스) 중심에 고정 스타일. Flint은 데이터 시각화 중심(30+ 통계 차트) + 의미 기반 자동 디자인.

vs Vega-Lite의 "스마트 기본값" — Vega-Lite 기본값은 저장 타입 기반. Flint은 그 위에 70개 시맨틱 레이어를 더해 통화 포맷·발산 색상·순위 역축처럼 Vega-Lite가 추론 못 하는 디자인 결정을 내린다.

3기술 스택 전체 지도

npm 워크스페이스 모노레포 — 코어 라이브러리 · MCP 서버 · Python 포팅 · 데모 사이트

Flint은 npm workspaces 모노레포다("name": "flint-chart-monorepo"). 네 개의 워크스페이스로 나뉘고, 엔진 요구사항은 Node ≥ 18이다. 흥미로운 설계 결정 하나 — 코어 라이브러리는 런타임 의존성이 0개이고, 실제 렌더러(Vega·ECharts·Chart.js)는 전부 선택적 peer dependency다. 즉 코어는 순수 TypeScript로 "스펙 객체"만 뱉고, 무거운 렌더링 라이브러리는 그걸 쓰는 쪽이 골라 설치한다.

워크스페이스배포 이름 · 역할
packages/flint-jsnpm flint-chart v0.2.2 — 코어 라이브러리(약 58,700줄). 시맨틱 해석 + 레이아웃 + 3개 백엔드 코드생성. TypeScript ESM+CJS.
packages/flint-mcpnpm flint-chart-mcp v0.2.2 — MCP 서버(약 3,800줄). 에이전트에게 차트 렌더/컴파일/검증 도구를 노출, 서버측 PNG 래스터화 포함.
packages/flint-pyPyPI flint-chart v0.1.0 — Python 포팅 프리뷰(약 13,000줄). 코어의 1:1 이식이나 현재 Vega-Lite 백엔드만. (미출시)
site/데모 사이트 — Vite + React + TS. 갤러리 · 라이브 에디터(CodeMirror) · 문서. 개발 서버 포트 5274.

코어 flint-chart (packages/flint-js)

언어는 TypeScript ^5.6, ESM 우선("type": "module", "sideEffects": false)에 CJS/ESM 이중 출력. 빌드는 tsup ^8.3, 테스트는 vitest ^4.1, 린트는 eslint ^9 + typescript-eslint ^8. 서브패스 export(./core, ./vegalite, ./echarts, ./chartjs, ./test-data, ./gallery)로 필요한 부분만 가져온다.

// packages/flint-js — peerDependencies (전부 optional: 쓰는 렌더러만 설치)
"peerDependencies": {
  "chart.js":  "^4.0.0",
  "echarts":   "^5.0.0 || ^6.0.0",
  "vega":      "^5.0.0 || ^6.0.0",
  "vega-lite": "^5.0.0 || ^6.0.0"
}
// ★ 코어 자체의 runtime dependencies = 0개 (순수 TS가 plain 객체를 반환)

MCP 서버 flint-chart-mcp (packages/flint-mcp)

바이너리 flint-chart-mcp(→ dist/cli.js)로 실행한다. 여기는 렌더러들을 실제 의존성으로 품는다 — 서버가 직접 PNG/SVG를 그려 에이전트에 돌려줘야 하기 때문이다.

의존성역할
@modelcontextprotocol/sdk ^1.29
@modelcontextprotocol/ext-apps ^1.7
MCP 프로토콜 SDK + MCP App UI(대화형 차트 뷰) 확장
vega ^6 · vega-lite ^6
vega-interpreter ^2.2
Vega 런타임. vega-interpreterCSP-safe(eval 없이) 실행 — 보안 샌드박스용
echarts ^6 · chart.js ^4.4나머지 두 백엔드 렌더러
@napi-rs/canvas · @resvg/resvg-js서버측 래스터화 — SVG→PNG, 캔버스 기반 PNG 출력
zod ^3.25MCP 도구 입력 스키마 검증(문법의 검증 표면)
(devDeps) react 19 · vite 8
vite-plugin-singlefile
대화형 "chart view" MCP App UI를 React 단일 파일 번들로 빌드

Python 포팅 flint-py · 데모 사이트

flint-py는 코어의 near 1:1 이식(파이썬 ≥ 3.10, 유일 런타임 의존성 python-dateutil). 도구체인은 uv(락파일) + ruff + pytest. JS 구현과의 "갤러리 패리티(parity)"를 자동 평가하는 하니스(tools/run_full_eval.py)까지 있어, 두 구현이 같은 결과를 내는지 공유 픽스처로 검증한다. 데모 site/는 Vega-Lite/ECharts/Chart.js 세 뷰 컴포넌트 + JSON 라이브 에디터로, flint-chart를 소스(packages/flint-js/src)로 alias 걸어 라이브러리 수정이 바로 hot-reload 된다.

4아키텍처 심화 분석

"프론트엔드 → 옵티마이저 → 코드 생성" — 차트를 위한 진짜 컴파일러

Flint은 스스로를 컴파일러로 명시한다. 공유되는 프론트엔드 + 옵티마이저가 있고, 백엔드마다 코드 생성기가 따로 있다. 핵심 통찰은 1·2단계(시맨틱 + 레이아웃)는 100% 백엔드 독립이고, 오직 3단계만 백엔드별로 다르다는 것. 그래서 새 렌더링 백엔드(예: Plotly)를 추가하려면 3단계만 구현하면 된다.

assembleVegaLite(input) // 또는 assembleECharts / assembleChartjs │ ▼ ══ 1단계 · 컴파일러 프론트엔드 (core/, 백엔드 독립) ═══════════════ resolveChannelSemantics() semantic_types + data → ChannelSemantics computeZeroDecision() 축별 0 기준선 필요 여부 declareLayoutMode() 어느 축이 "밴드형(discrete)"인지 선언 convertTemporalData() 의미 기반 날짜 파싱 │ ▼ ══ 2단계 · 옵티마이저 (core/, 백엔드 독립) ═══════════════════════ computeChannelBudgets() + filterOverflow() 안 들어가는 항목 제거 + 경고 computeLayout() 물리 기반 크기 결정: · 이산 축 → Elastic Budget (막대·히트맵 셀) [스프링] · 연속 축 → Gas Pressure (산점도·라인) [가스 압력] · 전역 → facet 격자, 종횡비, 방사/면적 모델 │ ▼ ══ 3단계 · 코드 생성기 (백엔드별: vegalite/ echarts/ chartjs/) ═══ build*Encodings() 백엔드 인코딩 객체 template.instantiate() 템플릿 훅이 네이티브 스펙 조립 applyLayoutToSpec() step, width/height, padding 적용 │ ▼ 네이티브 스펙 (+ 선택적 ChartWarning[])

이 파이프라인의 중심 오케스트레이션은 packages/flint-js/src/vegalite/assemble.ts(1,152줄)에 있다. 아래는 이 컴파일러를 떠받치는 세 가지 핵심 설계 패턴이다.

설계 패턴 ① 동적 템플릿(Dynamic Template) — 전략 + 레지스트리

모든 chartType 이름은 하나의 ChartTemplateDef에 매핑된다. 백엔드마다 레지스트리(vlTemplateDefs 등)가 있고 이름으로 조회한다. 30개가 넘는 차트가 전부 같은 인터페이스를 구현하되, 생명주기 훅(declareLayoutModenormalizeEncodingsinstantiatepostProcess)으로 개별 동작을 끼워 넣는 플러그인 아키텍처다.

// core/types.ts — 모든 차트 타입이 구현하는 계약
interface ChartTemplateDef {
  chart: string;                    // "Bar Chart" — chart_spec.chartType과 일치
  template: any;                    // 네이티브 스펙 골격 { mark:"bar", encoding:{} }
  channels: string[];               // 허용 인코딩 채널
  markCognitiveChannel: 'position'|'length'|'area'|'color';
                                    // 마크가 크기를 어떻게 표현하나 → 0기준선·stretch 클래스 결정
  declareLayoutMode?: (cs, table) => LayoutDeclaration;  // 어느 축이 밴드형?
  instantiate: (spec, ctx) => void;                      // 최종 스펙 조립
  properties?: ChartPropertyDef[];       // 조절 노브(예: cornerRadius)
  pivot?: PivotDef;                      // named-view 변환(패턴 ③)
}
// vegalite/templates/bar.ts — 패턴 전체가 ~30줄에 담긴다
export const barChartDef: ChartTemplateDef = {
  chart: "Bar Chart",
  template: { mark: "bar", encoding: {} },
  channels: ["x","y","color","group","opacity","column","row"],
  markCognitiveChannel: 'length',        // 막대는 "길이"로 크기 표현
  declareLayoutMode: (cs, table) => {
    const r = detectBandedAxisFromSemantics(cs, table, { preferAxis: 'x' });
    return { axisFlags: r ? { [r.axis]: { banded: true } } : { x: { banded: true } } };
  },
  instantiate: (spec, ctx) => {
    defaultBuildEncodings(spec, ctx.resolvedEncodings);
    if (ctx.chartProperties?.cornerRadius > 0)
      spec.mark = setMarkProp(spec.mark, 'cornerRadius', ctx.chartProperties.cornerRadius);
    adjustBarMarks(spec, ctx);
  },
  encodingActions: [makeSortAction()],
  pivot: makeCartesianPivot({ transpose: [['x','y']], permute: [['x','y','color']] }),
};

설계 패턴 ② 물리 기반 auto-layout

옵티마이저는 두 숫자에서 출발한다 — baseSize(차트가 지향하는 목표 크기, 기본 400×320)와 canvasSize(절대 넘으면 안 되는 상한, 기본 = baseSize × maxStretch, maxStretch 기본 1.5×). 데이터가 늘면 기하 형태별로 다른 물리 모델로 크기를 키운다.

모델기하 · 대상 차트아이디어
Elastic Budget1D 밴드 축 · 막대·히스토그램·히트맵·박스플롯안식 길이 L₀를 가진 스프링. 범주가 늘면 넓어지고, 최소 가독 스텝까지 압축되다, 한계 넘으면 overflow
Gas Pressure2D 점 구름 · 산점도·라인·면적점 밀도에 따라 축이 가스 압력(수요÷공급)처럼 부드럽게 늘어남
Circumference1D 닫힌 고리 · 파이·로즈·선버스트·레이더·게이지슬라이스가 붐비면 반지름을 키워 원주 가독성 유지
Area (2D)2D 채움 · 트리맵모든 사각형이 읽히도록 캔버스 면적을 키움

데이터가 그래도 안 들어가면 overflow 필터가 항목을 버리고 ChartWarning 메타데이터를 붙인다 — 읽을 수 없는 차트를 그리느니 경고와 함께 잘라낸다. 이 "물리를 레이아웃 휴리스틱으로" 쓰는 발상은 "제한된 공간에 콘텐츠 맞추기"라는 온갖 문제에 전이 가능한 아이디어다(라인 차트의 banking-to-45° 종횡비 최적화도 포함).

설계 패턴 ③ Named Views = 군(group)의 궤도(orbit)

차트 변형(축 뒤집기, 계열↔색상 교환, facet, 형제 차트로 전환)을 매번 스펙 재작성으로 얻는 대신, Flint은 이를 4개 생성원(generator)이 만드는 궤도로 모델링한다. 원저작 배치 a0에서 시작해 아래 연산을 조합해 걷는다.

기호생성원의미
τ (tau)transpose두 축 슬롯을 통째로 전치(flip:x-y)
σ (sigma)permute같은 프로파일 채널끼리 교환(swap:y-color, 측정값↔측정값)
γ (gamma)shift이산 계열 필드를 color/group/facet 채널 사이로 라우팅
θ (theta)transition같은 필드를 형제 템플릿으로 다시 렌더(type:Strip Plot)

중복 제거는 안정자 몫(stabilizer quotient)을 코드로 구현한 것이다 — flip을 두 번 하면 항등(identity), facet 후 jitter가 Strip Plot로 접히는 등 같은 상태로 수렴하는 변형을 자동 병합한다. 호환성은 타입으로 강제된다(σ는 같은 프로파일만, τ는 슬롯을 바꾸므로 프로파일을 넘나들 수 있음). 라인 차트는 τ를 생략해 "세로 라인 차트" 같은 무의미한 변형을 아예 제안하지 않는다. 구현은 core/pivot.ts. 추상대수(궤도·생성원·안정자)를 실전 UI 상태 열거에 쓴, 보기 드문 사례다.

중심 입력 타입 · Flint "프로그램"의 모양
ChartAssemblyInput
Flint에 넣는 최상위 입력은 data + semantic_types + chart_spec(+ options)로 이뤄진다. data는 인라인 행({values:[...]})이나 로컬 파일 경로({url:"..."}). chart_spec 안에 chartType·encodings·선택적 baseSize/canvasSize/chartProperties가 들어간다. 인코딩에서 맨 문자열은 {field}의 축약이다(예: y: "mpg" = y: {field:"mpg"}).

5디렉토리 구조 해부

모노레포 3+1 패키지 — 그리고 지적 심장 core/

클론 직후의 최상위 구조와, 코어의 내부다. HEAD 커밋은 8e8d1d2, 전체 2,587 파일에 TS/Py 실코드 약 86,600줄이다.

flint-chart/ ├── package.json npm-workspaces 루트(빌드/테스트/사이트 오케스트레이션, Node ≥18) ├── README.md CHANGELOG.md LICENSE(MIT) ├── scripts/ gen-chart-reference.ts(백엔드 레퍼런스 문서 자동생성) ├── shared/test-data/ JSON 픽스처 — JS·Python 양쪽이 공유(패리티 검증) │ ├── packages/ │ ├── flint-js/ ← npm `flint-chart` (코어 TS 라이브러리, ~58,700줄) │ │ └── src/ │ │ ├── index.ts 공개 배럴: assembleVegaLite/ECharts/Chartjs │ │ ├── core/ ★ 1~2단계, 백엔드 독립 (아래 표) │ │ ├── vegalite/ 3단계 — assemble.ts + templates/ (차트 30종) │ │ ├── echarts/ 3단계 — + colormap.ts, facet.ts (35파일) │ │ ├── chartjs/ 3단계 — + colormap.ts, templates/ (20파일) │ │ ├── test-data/ TEST_GENERATORS — 테스트 겸 갤러리 픽스처 │ │ └── gallery/ 갤러리 설정 │ │ │ ├── flint-mcp/ ← npm `flint-chart-mcp` (MCP 서버, ~3,800줄) │ │ ├── src/cli.ts 진입점(stdio/http 트랜스포트, 플래그) │ │ ├── src/server.ts MCP 도구/리소스/프롬프트 등록 │ │ ├── src/http.ts Streamable-HTTP 트랜스포트(기본 /mcp) │ │ ├── src/tools/ compile.ts, validate.ts, list.ts, schemas.ts(zod) │ │ ├── src/render/ 인프로세스 래스터화: vegalite/echarts/chartjs/svg/fonts │ │ ├── ui/ React 단일파일 "chart view" MCP App │ │ └── assets/ 번들된 skill + chart-view html │ │ │ └── flint-py/ ← Python 포팅 프리뷰 (Vega-Lite만, ~13,000줄) │ ├── flint/core/ 코어의 1:1 이식(compute_layout.py, field_semantics.py…) │ ├── flint/vegalite/ assemble.py + templates/(bar.py, line.py…) │ └── tools/ run_full_eval.py(JS 대비 패리티 평가) + HTML 뷰어 │ ├── agent-skills/ │ └── flint-chart-author/SKILL.md ★ 566줄 에이전트 작성 가이드(MCP에도 번들) ├── site/ Vite+React 데모(랜딩·갤러리·라이브 에디터·문서) 포트 5274 └── docs/ ★ 아키텍처+설계 문서(총 6,208줄) ├── architecture.md 3단계 파이프라인 + named-views 군론 ├── design-semantics.md (863) 3계층 시맨틱 타입 시스템 ├── design-stretch-model.md (1,110) 물리 기반 레이아웃 수식 ├── api-reference.md ChartAssemblyInput, overflow 전략 └── adding-a-{backend,chart-template,semantic-type}.md 확장 가이드

core/가 이 프로젝트의 지적 핵심이다(백엔드 독립 1·2단계). 파일 크기순으로 무엇이 있는지 보면 "이 컴파일러가 진짜로 무슨 일을 하는지"가 드러난다.

파일(core/)크기역할
compute-layout.ts78KB레이아웃 엔진 — elastic budget, gas pressure, 원주, 면적, facet 격자
types.ts50KB모든 코어 타입(ChartAssemblyInput, ChartTemplateDef, ChannelSemantics…)
recommendation.ts49KB채널 역할 추천·적응(adaptChannels / recommendChannels)
semantic-types.ts42KB시맨틱 타입 카탈로그 + 격자(lattice) + 0결정·색상·범주 추론
field-semantics.ts42KB필드별 해석: 포맷·집계·도메인·눈금·발산·정규 정렬
decisions.ts38KB재사용 결정 함수: computeElasticBudget, computeGasPressure, computeOverflow…
pivot.ts26KBnamed-view / pivot 열거 + 합성(군의 궤도)
type-registry.ts15KB단일 진실원 TYPE_REGISTRY: 타입→시각 범주+기본값
static-series.ts10KBwide→long "static-series fold"(배열 인코딩)
읽는 순서 · 어디부터 파나
README → docs/overview → docs/architecture → core/types.ts → vegalite/templates/bar.ts
README.md로 전체 그림과 갤러리를 잡고 → ② docs/overview.md(동기·dataSpec/chartSpec 분리) → ③ docs/architecture.md(3단계 + named-views) → ④ core/types.ts에서 계약을 확인 → ⑤ vegalite/templates/bar.ts 같은 가장 단순한 템플릿 하나를 통독하면 "짧은 스펙이 네이티브 스펙으로 변하는" 전 과정이 손에 잡힌다. 백엔드는 하나(vegalite)만 깊게 보고 나머지는 차이만 훑는 게 효율적이다.

6학습 포인트

"프로그래밍 언어가 아닌 도메인을 위한 컴파일러 설계"가 통째로 담긴 표본

Flint이 학습 표본으로 훌륭한 이유는 컴파일러 아키텍처, 계층형 타입 시스템, 물리 휴리스틱, 군론 응용, 플러그인 패턴, MCP 서버 엔지니어링, 에이전트 프롬프트 설계, 크로스언어 포팅이 한 저장소에 모여 있기 때문이다. 관심사별로 짚어 보자.

① 비(非)-언어 도메인에 적용한 컴파일러/IL 설계

프론트엔드/옵티마이저/코드생성 분리, "중간 표현(IR)" 프레이밍, "하나의 입력 → 여러 타깃"은 교과서적 컴파일러 구조를 차트라는 비-프로그래밍 도메인에 적용한 것이다. core/는 타깃 독립, vegalite|echarts|chartjs/는 백엔드 코드 생성기. "PL이 아닌 대상을 위한 컴파일러를 어떻게 짜는가"를 배우기 딱 좋다.

② 파서 없는 DSL / 문법 설계

Flint의 "언어"는 JSON 모양(ChartAssemblyInput)이라 렉서/파서 대신 정규화 + 축약 확장(맨 문자열 → {field})과 zod 스키마(MCP 계층)를 문법의 검증 표면으로 쓴다. "DSL이 꼭 자체 파서를 가질 필요는 없다 — 임베디드/JSON DSL도 엄밀한 타이핑이 가능하다"는 교훈.

③ graceful degradation을 갖춘 3계층 타입 시스템

type-registry.ts·semantic-types.ts3계층 격자(Family → Category → Specific)는, 거친 라벨(Measure)만 줘도 "일반적이지만 올바른" 결과를 내고 구체 라벨(Price)을 주면 완전한 포맷팅을 푼다. 불완전한/LLM 입력을 견디도록 설계하는 아름다운 예다. (README의 "70+ 타입" = Family 6 + Category 17 + Specific 46 ≈ 69개.)

④ 레이아웃 휴리스틱으로서의 물리

decisions.ts + compute-layout.ts + design-stretch-model.md. 축 크기를 스프링(elastic budget)·가스 압력으로 모델링하는 건 "제한 공간에 콘텐츠 맞추기"라는 온갖 문제에 전이 가능한 발상이다(라인 차트 banking-to-45° 종횡비 최적화 포함).

⑤ 실전 소프트웨어 속의 군론

pivot.ts의 궤도·생성원·안정자 몫으로 UI 상태를 열거·중복제거하는 건 추상대수의 드문 실전 응용이다. "이론이 코드가 되는" 감을 잡기에 최고의 사례.

⑥ 대규모 전략 + 레지스트리 패턴 · MCP 서버 엔지니어링

30+ 템플릿이 같은 ChartTemplateDef 인터페이스를 생명주기 훅으로 구현한 플러그인 구조. 그리고 flint-mcp/는 라이브러리를 에이전트에게 MCP 도구(render_chart·compile_chart·validate_chart·list_chart_types·create_chart_view), 리소스(flint://chart-types·flint://agent-skill), 프롬프트(author_flint_chart)로 노출하는 법 — stdio/HTTP 두 트랜스포트, CSP-safe 인프로세스 래스터화까지 — 실전 교본이다.

⑦ 에이전트 지향 프롬프트 설계 · 크로스언어 포팅

agent-skills/flint-chart-author/SKILL.md(566줄)는 "LLM을 위한 지시문"의 마스터클래스 — 정확한 차트 타입 표, "변환/필드명을 지어내지 말라", 데이터 정합성 체크리스트. 순수 프롬프트 엔지니어링 자료로도 값지다. flint-py는 공유 픽스처(shared/test-data/) + 패리티 평가로 두 구현을 동기화하는 규율을 보여 준다.

실습 아이디어 · 작게 시작하기
지금 당장 손에 익힐 3가지
npx -y flint-chart-mcp로 MCP 서버를 띄워 에이전트(Claude/VS Code)에 붙이고 CSV로 첫 차트를 그려 본다. ② semantic_types에서 PriceTemperatureRank를 바꿔 가며 포맷·색상·축 방향이 어떻게 자동으로 달라지는지 관찰한다. ③ docs/adding-a-semantic-type.md를 보고 새 타입(Rating 등)을 하나 추가해 본다. 이 셋만 해도 "의미가 디자인을 결정한다"는 핵심이 몸에 붙는다.

7시스템 요구사항 · 설치

Node ≥ 18 (JS) · Python ≥ 3.10 (프리뷰) · 코어는 런타임 의존성 0개

Flint은 특별한 하드웨어가 필요 없다 — 순수 계산이라 GPU도 무관하다. 라이브러리로 쓰든, 에이전트용 MCP 서버로 쓰든 설치는 간단하다.

# 1) 라이브러리로 쓰기
npm install flint-chart
npm install vega vega-lite vega-embed   # 브라우저에서 Vega-Lite 렌더 시
npm install echarts                     # ECharts 백엔드
npm install chart.js                    # Chart.js 백엔드

# 2) 에이전트용 MCP 서버(전역 설치 불필요)
npx -y flint-chart-mcp

MCP 클라이언트(VS Code .vscode/mcp.json 또는 일반 mcpServers) 설정은 이렇게 한다.

{
  "mcpServers": {
    "flint-chart": { "command": "npx", "args": ["-y", "flint-chart-mcp"] }
  }
}
항목요구 / 설명
런타임Node ≥ 18(JS) · Python ≥ 3.10(소스 전용 프리뷰). 브라우저 표시엔 렌더러 라이브러리 필요
가속기불필요 — 순수 스펙 변환. 무거운 건 렌더러가 담당
MCP 트랜스포트--transport <stdio|http>(기본 stdio) · http는 --port/--host
백엔드 제한--backends vegalite,echarts로 활성 백엔드 한정 가능
하드닝 모드--disable-file-reference — 에이전트가 로컬 파일을 못 읽고 data.values 인라인만 허용(원격 URL은 애초에 안 가져옴)
데이터 입력인라인 data.values 또는 로컬 .json/.csv/.tsv 경로(data.url)
# 기여/개발 (저장소 루트에서)
git clone https://github.com/microsoft/flint-chart && cd flint-chart
npm install        # workspaces: flint-js + flint-mcp + site
npm run typecheck  # tsc
npm run test       # Vitest (JS+MCP);  npm run test:py → uv run pytest
npm run build      # tsup가 두 npm 패키지 빌드
npm run site       # http://localhost:5274 갤러리+에디터

8직접 해볼 수 있는 실습 과제

난이도별 5개 — 첫 컴파일부터 새 백엔드 코드 생성기 추가까지
난이도 ★☆☆ · 초급

과제 1 — 하나의 입력, 세 백엔드

assembleVegaLite·assembleECharts·assembleChartjs같은 입력을 넣고 출력 스펙 셋을 나란히 찍어 본다.

import { assembleVegaLite, assembleECharts, assembleChartjs } from 'flint-chart';
const input = {
  data: { values: myData },
  semantic_types: { weight: 'Quantity', mpg: 'Quantity', origin: 'Country' },
  chart_spec: { chartType: 'Scatter Plot',
    encodings: { x: {field:'weight'}, y: {field:'mpg'}, color: {field:'origin'} } },
};
assembleVegaLite(input); assembleECharts(input); assembleChartjs(input);

목표: "하나의 IL → 여러 타깃"이라는 컴파일러 핵심을 눈으로 확인.

난이도 ★☆☆ · 초급

과제 2 — 시맨틱 타입이 디자인을 바꾼다

같은 수치 열의 semantic_typesQuantityPriceTemperatureRankPercentage로 바꿔 가며 통화 포맷·0 기준선·발산 색상·역축·퍼센트 도메인이 자동으로 달라지는지 관찰한다. 202401 열은 YearMonth로 지정해 시간 축이 되는지 확인. 목표: Flint의 정체성 "의미 = 디자인"을 체감.

난이도 ★★☆ · 중급

과제 3 — wide→long fold + facet

y 채널에 배열(y: ["sales","profit"])을 넣어 여러 측정 열을 계열로 접는 static-series fold를 써 보고, column: {field:"region"}으로 지역별 패널(facet)을 만든다. "fold가 color를 소유하므로 color를 따로 못 준다"는 제약도 확인. 목표: 내장 리셰이프와 facet 레이아웃 이해.

난이도 ★★☆ · 중급

과제 4 — 에이전트에 MCP 붙여 CSV→차트

npx -y flint-chart-mcp를 Claude/VS Code에 연결하고, 로컬 CSV를 주며 "지역별 매출을 큰 순서로, region별 패널로 그려 줘"라고 시킨다. create_chart_view대화형 차트 뷰를 띄우고, validate_chart가 잡아 주는 실수(잘못된 차트 이름 등)를 관찰한다. 목표: "에이전트가 신뢰성 있게 차트를 그린다"는 워크플로 실측.

난이도 ★★★ · 고급

과제 5 — 네 번째 백엔드 추가(3단계만)

docs/adding-a-backend.md를 따라 Plotly나 D3용 코드 생성기를 새로 만든다. 1·2단계(시맨틱·레이아웃)는 손대지 않고 3단계 코드 생성만 구현하면 된다는 아키텍처의 힘을 직접 검증한다. 여유가 되면 docs/adding-a-chart-template.md로 새 차트 타입을 하나 추가. 목표: "백엔드 독립 프론트엔드"의 실전 이점을 체득.

9관련 기술 심화 학습 로드맵

4주 코스 — 시각화 문법 → 컴파일러 이론 → MCP·에이전트 → 타입/군론·물리 레이아웃
주차주제 · 학습 목표
1주차
시각화 문법
Grammar of Graphics의 계보. Wilkinson의 그래픽 문법과 Vega-Lite(Satyanarayan 등)를 익혀 Flint이 "그 위에" 앉는 이유를 이해. Vega-Lite 스펙을 손으로 몇 개 써 보고, 왜 저장 타입만으론 부족한지 체감.
2주차
컴파일러 이론
프론트엔드/IR/코드생성 분리. 중간표현(IR), 다중 타깃 코드 생성, 옵티마이저 패스 개념. Flint의 core/(타깃 독립)와 백엔드 코드생성기를 대조하며 "PL이 아닌 컴파일러"를 읽는다.
3주차
MCP · 에이전트 도구
에이전트에 도구를 노출하기. Model Context Protocol(도구·리소스·프롬프트, stdio/HTTP), zod 스키마 검증, 서버측 래스터화. flint-mcpSKILL.md를 교본 삼아 "LLM을 위한 API·프롬프트 설계".
4주차
타입 격자 · 군론 · 물리
불완전 입력을 견디는 설계. 타입 격자(lattice)와 graceful degradation, 군(orbit·generator·stabilizer)으로 상태 열거, 물리(스프링·가스 압력)를 레이아웃 휴리스틱으로. type-registry.ts·pivot.ts·compute-layout.ts를 정독.

10핵심 키워드 사전

이 문서에서 반드시 챙길 용어 14개
용어 01
Flint · 시각화 IL(중간언어)
차트 라이브러리를 "실행 타깃"으로 삼는 상위 컴파일러. 짧은 스펙을 Vega-Lite/ECharts/Chart.js 네이티브 스펙으로 컴파일한다.
용어 02
시맨틱 타입(Semantic Type)
저장 타입이 아니라 "의미"(Price·YearMonth·Rank·Correlation…). 포맷·색상·축 방향 같은 디자인을 결정. Family→Category→Specific 3계층(약 69개).
용어 03
graceful degradation
거친 라벨(Measure)만 줘도 올바른 일반 결과, 구체 라벨(Price)을 주면 완전한 포맷팅. 불완전/LLM 입력을 견디는 설계.
용어 04
ChartAssemblyInput
Flint "프로그램"의 최상위 입력. data + semantic_types(dataSpec) + chart_spec(chartSpec) + options.
용어 05
dataSpec vs chartSpec
semantic_types=열의 의미(데이터셋 단위로 재사용), chart_spec=차트 타입+채널 바인딩(값싸게 편집하는 부분). 둘을 분리한 게 핵심 설계.
용어 06
Channel · Encoding
채널=시각 슬롯(x·y·color·size·column·row…). 인코딩={field, type?, aggregate?, sortOrder?, sortBy?, scheme?}를 채널에 바인딩. 맨 문자열은 {field} 축약.
용어 07
ChannelSemantics
1단계 출력. 채널별로 해석된 백엔드 독립 레코드(인코딩 타입·포맷·0결정·정렬·도메인).
용어 08
ChartTemplateDef · 동적 템플릿
차트 타입별 전략 객체. 생명주기 훅(declareLayoutMode→normalizeEncodings→instantiate→postProcess)을 가지며 백엔드 레지스트리에서 이름으로 조회된다.
용어 09
markCognitiveChannel
마크가 크기를 어떻게 표현하나: position | length | area | color. 0 기준선 강제 여부와 stretch 클래스를 결정.
용어 10
static-series fold
유일한 내장 리셰이프. x/y에 배열을 주면 여러 wide 열을 long 형태로 접고 계열 키+값 열을 합성(그 대신 color는 fold가 소유).
용어 11
Elastic Budget · Gas Pressure
물리 기반 레이아웃 모델. 이산 축은 스프링(elastic budget), 연속 축은 가스 압력. 그 외 원주(파이류)·면적(트리맵) 모델도.
용어 12
baseSize vs canvasSize
지향 목표 크기(기본 400×320) vs 절대 상한(= base × maxStretch, 기본 1.5×). β=차원별 stretch 배수.
용어 13
Named View · pivot(τ σ γ θ)
차트 변형을 4개 생성원(전치·치환·이동·전환)의 궤도로 열거. 중복은 안정자 몫으로 제거. core/pivot.ts.
용어 14
MCP 도구 · 에이전트 스킬
render_chart·compile_chart·validate_chart·list_chart_types·create_chart_view 도구 + 566줄 flint-chart-author 스킬(flint://agent-skill 리소스로도 제공).

11참고 링크

저장소 · 라이브 에디터 · 갤러리 · MCP 가이드 · npm · 문서

저장소 & 배포
· GitHub: github.com/microsoft/flint-chart (MIT)
· npm 코어: npmjs.com/package/flint-chart · MCP: npmjs.com/package/flint-chart-mcp

프로젝트 사이트(문서 · 갤러리 · 라이브 에디터)
· 홈: microsoft.github.io/flint-chart
· 라이브 에디터: /#/editor · 갤러리: /#/gallery · MCP 가이드: /#/mcp

저장소 내 핵심 문서
· docs/architecture.md(3단계 + named-views 군론) · docs/overview.md(동기) · docs/design-semantics.md(시맨틱 3계층) · docs/design-stretch-model.md(물리 레이아웃 수식) · docs/api-reference.md · agent-skills/flint-chart-author/SKILL.md

제작
· Microsoft Research (microsoft.com/research) × 런민대 IDEAS Lab (ideas-lab.net) · 논문 "coming soon"