.md 파일에 같이 담아, 세션이 바뀌어도 Cursor·Claude Code 같은 코딩 AI가 똑같은 브랜드 감각으로 화면을 만들게 한다. 단순 스펙 문서가 아니라, 그 파일을 검사·비교·변환하는 CLI 도구(@google/design.md)까지 함께 들어 있는 모노레포다. (저장소: google-labs-code/design.md · TypeScript 95.6% · ★15.8k · Apache-2.0 · 포맷 버전 alpha · TrendShift Daily #7)이 레포가 무엇을 하는 물건인가.
primary: #1A1C1E 라고만 적으면 AI는 '검정이구나'까지만 안다.디자인 값(토큰)만 넘기면 AI는 '무엇'은 알아도 '왜·언제 쓰는지'를 모른다. design.md는 값과 의도를 한 파일에 묶어, 대화가 끊겨도 같은 디자인 정체성을 유지하게 한다.
design.md는 "비주얼 아이덴티티(디자인 시스템)를 코딩 에이전트에게 설명하기 위한 파일 포맷"이다. DESIGN.md라는 파일 하나에 두 개의 층을 담는다 — ① 맨 위 YAML front matter에 색·글꼴·간격 같은 정확한 값(토큰)을, ② 그 아래 Markdown 본문에 "이 색은 화면에서 가장 중요한 행동 하나에만 쓴다" 같은 적용 맥락(prose)을 적는다.
레포의 한 줄 설명이 이 철학을 압축한다 — "Tokens give agents exact values. Prose tells them why those values exist and how to apply them." (토큰은 정확한 값을 주고, 글은 그 값이 왜 존재하고 어떻게 쓰는지를 알려준다.) 즉 design.md는 "렌더링 명령서"가 아니라 AI에게 건네는 참고 맥락(reference context)이다.
DESIGN.md를 두면, 코딩 AI가 그걸 읽고 그 브랜드에 맞는 UI를 만든다. 식당으로 치면 '우리 가게 분위기 설명서' — 메뉴(코드)가 아니라 '이 집은 이런 느낌'을 적어둔 쪽지다.#6d52a3라는 색에 primary라는 이름을 달아두면, 곳곳에서 "보라색"이 아니라 "primary"라고 부른다. 한 곳만 바꾸면 전부 따라 바뀌는 '색깔 단축번호'인 셈.--- 두 줄 사이로 끼워 넣는 기계가 읽는 설정 영역이다. 블로그에서 글의 제목·날짜를 적던 그 자리. design.md는 여기에 디자인 토큰을 YAML 형식으로 적어, 사람용 본문과 기계용 데이터를 한 파일에서 깔끔히 나눈다.트렌딩 이유 · 기존 방식 대비 장점.
화제의 핵심은 세 가지가 겹친 데 있다 — ① Google Labs가 직접 낸 레포(공식 디자인 도구 Stitch와 연계, 정식 스펙은 stitch.withgoogle.com에 호스팅), ② "토큰보다 글이 중요하다"는 역발상, ③ 에이전트 스킬이 트렌딩을 휩쓰는 2026년 흐름. 공개 직후 ★15.8k를 모으며 같은 날 TrendShift 상위에 올랐다.
가장 신선한 주장은 "디자인 품질은 값의 정밀함보다 의도가 얼마나 분명히 적혔는가로 결정된다"는 것이다. 흔한 디자인 토큰 파일(JSON)은 값만 잔뜩 담지만, AI는 그 값을 '왜' 쓰는지 몰라 엉뚱한 곳에 강조색을 칠한다. design.md는 그 빈틈을 prose(글)로 메운다.
| 항목 | 기존 방식(Design Tokens JSON · Figma 변수 · 스타일가이드 PDF) | design.md |
|---|---|---|
| 담는 것 | 값(토큰)만 — 색·폰트·간격 숫자 | 값 + "왜/언제 쓰는지" 글을 한 파일에 |
| AI 소비 | 값은 읽지만 의도를 추론 못 함 | 토큰=정확값, prose=의도 → 빈칸도 추론 |
| 형식 | 전용 JSON/디자인 툴(편집기 필요) | 그냥 .md 텍스트(어디서나 열림) |
| 버전 관리 | 바이너리/툴 종속이라 diff 어려움 | git diff 그대로, CLI diff로 회귀 검사 |
| 검증 | 수작업 또는 별도 도구 | 내장 린터 9룰(대비·깨진 참조·순서…) |
"글이 중요하다"가 단순 구호가 아니라 설계 곳곳의 결정으로 드러난다 — 린터는 모르는 섹션·토큰을 만나도 에러 없이 받아들이고(확장 자유), export는 토큰을 Tailwind나 W3C 표준(DTCG)으로 변환해주며, spec 명령은 스펙 전체를 출력해 AI 프롬프트에 그대로 주입할 수 있게 한다.
토큰 JSON에 #2E7D32라고만 적으면 AI는 그 정확한 초록은 알지만 "이게 성공 메시지용인지, 브랜드 메인인지"를 모른다. 반대로 "친근하고 활기찬 느낌"이라는 형용사만 주면 너무 막연해 매번 다른 결과가 나온다. 값만으로도, 형용사만으로도 의도가 새어 나간다.
철학 문서(PHILOSOPHY.md)의 비유가 압권이다 — "1970년대 유서 깊은 대학의 강의 유인물" 한 문장이 수치 12개보다 많은 정보를 담는다. 그런 레퍼런스를 적으면 모델은 "그런 유인물엔 그라데이션·발광 효과가 없다"는 하지 말아야 할 것까지 자동으로 추론한다. design.md는 토큰(점)과 prose(구체적 레퍼런스)를 같이 줘서 의도를 좁힌다.
포맷 본체 · CLI 도구 · 디자인 토큰 생태계.
이 레포는 두 개의 얼굴을 가진다 — 하나는 코드가 없는 '포맷 명세'(Markdown + YAML 규칙), 다른 하나는 그 포맷을 다루는 실제 TypeScript CLI 도구다. 그래서 스택도 둘로 갈린다.
| 레이어 | 기술 / 버전 | 역할 |
|---|---|---|
| 포맷 본체 | Markdown + YAML front matter | 사람·기계가 같이 읽는 .md 파일 형식 그 자체 |
| 언어 | TypeScript 95.6% (strict) | CLI·린터 전체 구현 |
| 빌드/패키지 | Bun 1.3.9 + Turborepo | 여러 패키지를 한 저장소에서 빌드하는 모노레포 |
| CLI 프레임워크 | citty | lint·diff·export·spec 서브커맨드 정의 |
| Markdown 파싱 | unified + remark-parse / -frontmatter / -mdx | .md 텍스트를 다루기 쉬운 트리(AST)로 변환 |
| 스키마 검증 | zod | front matter의 YAML이 규칙에 맞는지 확인 |
| 색 처리 | 자체 color-parser | 모든 CSS 색을 sRGB로 변환해 대비(WCAG) 계산 |
| 토큰 출력 | DTCG(W3C) · Tailwind v3/v4 | 토큰을 외부 디자인 생태계 형식으로 변환 |
| 테스트/CI | bun test · GitHub Actions | 룰마다 .test.ts 페어 + Node·Windows 스모크 |
| 배포 | npm @google/design.md | npx로 설치 없이 바로 실행 |
.md를 AST로 바꿔 front matter·섹션을 정확히 집어낸다.export --format dtcg는 토큰을 이 표준으로 뽑아, 다른 디자인 툴과 서로 주고받게 한다.전체 그림 한 장 → 대표 흐름(lint) 한 줄기 추적.
먼저 숲을 보자. DESIGN.md 파일 하나가 두 갈래로 소비된다 — (A) AI 에이전트가 그냥 텍스트로 읽어 UI를 만들거나, (B) @google/design.md CLI가 기계적으로 검사·변환한다. 같은 파일이 사람·AI·도구 모두에게 통하는 게 이 설계의 핵심이다.
이제 흐름 한 줄기를 손으로 따라가 보자. 가장 대표적인 동작인 lint(파일 검사)를 실행하면 무슨 일이 순서대로 벌어지는가 — 곁가지(에러 처리·옵션)는 접고 해피패스만 본다.
# 사용자가 터미널에 친 한 줄 npx @google/design.md lint DESIGN.md # 그 안에서 벌어지는 일 (해피패스) ① remark-parse DESIGN.md 텍스트 → AST(제목·문단·front matter로 분해) ② frontmatter --- 사이 YAML을 꺼냄 ③ zod 검증 colors/typography/spacing… 모양이 규칙에 맞는지 확인 ④ 토큰 모델 color-parser가 #1A1C1E·oklch(...) 등을 sRGB로 환산 ⑤ 9룰 순회 broken-ref → missing-primary → contrast-ratio → … ⑥ findings 결과를 JSON으로 출력 · 에러 1개라도 있으면 exit 1
여기서 design.md 특유의 "정상적인 모양새" 세 가지를 짚어두면 코드가 덜 낯설다.
.md가 기계가 읽는 층(YAML 토큰)과 사람이 읽는 층(Markdown 글)을 위아래로 포갠다. 토큰은 '규범값(normative)' — 정확히 따라야 할 값이고, prose는 그 값을 어떤 맥락에서 쓰는지 설명한다. 둘이 같은 파일에 있어 서로 어긋날 일이 적다.docs/spec.md는 손으로 쓰지 않는다. spec-config.yaml + spec.mdx 한 곳을 고치고 bun run spec:gen을 돌리면 자동 생성된다(파일 맨 위에 "직접 편집 금지" 표시). 규칙을 한 군데서만 관리해 문서·코드·CLI 출력이 절대 어긋나지 않게 한 것.## Iconography)·모르는 토큰명을 만나도 에러 없이 받아들인다(값이 유효하면). 덕분에 스펙을 안 고쳐도 motion: 같은 커스텀 토큰을 마음껏 더할 수 있다. 단 하나의 예외 — 같은 섹션(## Colors)이 두 번 나오면 파일을 거부한다(중복은 곧 모순이므로).스펙 문서 · 예제 3종 · CLI 패키지 · 에이전트 개발 스킬.
모노레포라 폴더가 여럿이지만 역할은 명확히 나뉜다 — 뿌리의 문서, examples/의 완성 예제, packages/cli/의 실제 도구, 그리고 특이한 .agents/skills/의 AI 개발 보조 스킬.
| 경로 | 역할 |
|---|---|
| README.md | 입구 문서. 포맷이 무엇인지 + 압축된 스펙 + CLI 4개 명령 사용법 |
| PHILOSOPHY.md | "왜 토큰보다 글인가"를 설득하는 철학 — 이 레포의 영혼 |
| docs/spec.md | 전체 정식 스펙. 토큰 타입·섹션 순서·소비 규칙 전부. 자동 생성물 |
| examples/* | 각 예제가 DESIGN.md+tokens.json+tailwind.config 3종 세트 — "스펙→토큰→프레임워크" 파이프라인 통째 학습 |
| packages/cli/src/linter/rules/ | 9개 룰이 각각 이름.ts + 이름.test.ts 페어. TDD의 산실 |
| .agents/skills/ | 레포를 AI 에이전트로 개발하며 쓴 스킬을 skills-lock.json으로 버전 고정 — '도구로 도구를 만든' 메타 사례 |
이 레포 한 채에서 뽑아낼 수 있는 기술별 배움.
가장 먼저 할 일은 실제 파일을 눈으로 보는 것이다. 위가 기계용 토큰(YAML), 아래가 사람용 설명(Markdown)으로 깔끔히 나뉘는 걸 확인하자.
# ── 기계가 읽는 층: front matter ── --- name: Heritage colors: primary: "#1A1C1E" # deep ink (깊은 잉크색) surface: "#F2EFE9" # warm limestone (따뜻한 석회색) typography: headline-lg: fontFamily: Public Sans fontSize: 32px lineHeight: 1.2 # 단위 없으면 fontSize의 배수 components: button-primary: backgroundColor: "{colors.primary}" # 토큰 참조 textColor: "{colors.surface}" --- # ── 사람이 읽는 층: prose ── ## Overview Heritage는 1970년대 유서 깊은 대학의 강의 유인물 같은 느낌이다. ## Colors primary 색은 화면당 가장 중요한 행동 하나에만 쓴다.
실습 아이디어: 위 {colors.primary}처럼 값을 직접 쓰지 않고 토큰 이름을 가리키는 방식(참조)이 왜 좋은지 — 색 하나 바꿀 때 몇 군데를 고쳐야 하는지 세어보라.
design.md의 파서는 .md를 글자가 아니라 AST(구문 트리)로 바꿔 다룬다. 이 생태계(unified·remark)는 블로그 빌더부터 문서 도구까지 두루 쓰여, 한 번 배워두면 활용처가 넓다.
# 개념만: .md 문자열이 이런 트리로 바뀐다
root
├─ yaml (front matter 토큰)
├─ heading "## Overview"
├─ paragraph "Heritage는 ..."
└─ heading "## Colors"
실습 아이디어: unified().use(remarkParse).use(remarkFrontmatter)로 아무 마크다운이나 파싱해 트리를 콘솔에 찍어보면 구조가 손에 잡힌다.
토큰을 한 곳(DESIGN.md)에 적어두면, CLI가 여러 형식으로 뽑아준다. "한 번 정의, 어디서나 사용"이라는 디자인 토큰의 정수를 체험할 수 있다.
npx @google/design.md export DESIGN.md --format tailwind # → Tailwind 테마 (v3 json 또는 v4 @theme 블록) npx @google/design.md export DESIGN.md --format dtcg # → W3C 표준(DTCG) 토큰 JSON — Figma/Style Dictionary 호환
실습 아이디어: 같은 DESIGN.md를 두 형식으로 뽑아 차이를 비교하고, Tailwind 출력을 실제 페이지에 적용해보라.
이건 코드보다 사고방식의 교훈이다. AI에게 "모던하고 깔끔하게"라고 하면 매번 다른 게 나온다. 대신 "1970년대 대학 강의 유인물"처럼 한 점을 정확히 찍는 레퍼런스를 주면, 모델이 '하지 말 것'까지 알아서 추론한다.
실습 아이디어: 어떤 UI든 프롬프트를 ① 형용사만, ② 구체적 레퍼런스로 두 번 줘서 결과 차이를 직접 보라.
9개 린트 룰이 각각 구현 파일과 테스트 파일로 짝지어 있다(broken-ref.ts ↔ broken-ref.test.ts). TDD(테스트를 먼저 쓰고 통과시키는 개발법)의 교과서적 사례라, 작은 규칙 하나를 읽으면 패턴이 보인다.
# 9룰 요약 (괄호 = 심각도) broken-ref(error) 존재하지 않는 토큰을 참조 missing-primary(warn) primary 색이 없음 contrast-ratio(warn) 글자/배경 대비가 WCAG AA(4.5:1) 미만 section-order(warn) 섹션이 정해진 순서를 어김 unknown-key(warn) colours: 같은 오타 감지 # + orphaned-tokens, missing-typography, token-summary, missing-sections
프로그램에서 직접 부를 수도 있다: import { lint } from '@google/design.md/linter' → report.findings / .summary / .designSystem.
가벼운 텍스트 도구 — 설치도 거의 필요 없다.
| 항목 | 요구사항 / 메모 |
|---|---|
| 실행 | npx @google/design.md ... — 전역 설치 없이 바로 실행 |
| 런타임 | Node.js 18+ (또는 Bun). 레포 개발은 Bun 1.3.9 |
| OS | 크로스플랫폼. Windows는 .md 명령명이 Markdown 파일 연결과 충돌 → 별칭 designmd 사용 |
| 자원 | 텍스트 처리라 메모리·디스크 부담 거의 없음 |
| 네트워크 | npx 첫 실행 시 패키지 내려받기만 필요 |
| 포맷 안정성 | 버전 alpha — 스펙이 바뀔 수 있음(README 명시) |
난이도별로 손을 움직여 보는 5가지.
레포의 examples/totality-festival/DESIGN.md를 골라 검사기를 돌린다. 어떤 경고가 나오는지, JSON 결과를 어떻게 읽는지 익힌다.
npx @google/design.md lint examples/totality-festival/DESIGN.md
name + colors(primary 필수) + typography 최소 세 가지만으로 파일을 만들고, lint가 경고 0개로 통과하게 다듬어 본다. primary가 없으면 어떤 경고가 뜨는지도 확인.
2번에서 만든 파일을 export --format tailwind로 변환해, 간단한 HTML/React 페이지의 테마로 붙여본다. "한 곳 정의 → 여러 곳 사용"을 체감하는 단계.
같은 토큰을 가진 DESIGN.md 두 개를 만들되, 하나엔 ## Overview/## Do's and Don'ts prose를 풍부히, 다른 하나엔 토큰만. 둘을 각각 Claude·Cursor에 주고 같은 화면을 만들게 해 결과 차이를 관찰한다 — 이 레포의 핵심 주장을 직접 검증.
linter/rules/에 규칙 하나를 더한다(예: "폰트 패밀리는 3개 이하"). 먼저 이름.test.ts에 실패하는 테스트를 쓰고(Red), 통과하도록 이름.ts를 구현(Green)한 뒤 정리(Refactor)하는 TDD 흐름을 그대로 따라가 본다.
이 레포를 발판으로 6주 코스.
| 주차 | 주제 | 학습 자료 |
|---|---|---|
| 1주 | Markdown · YAML · front matter 기초 | MDN, 레포 README의 Heritage 예제 따라쓰기 |
| 2주 | 디자인 토큰 · DTCG · Tailwind 테마 | designtokens.org, Tailwind 문서, examples/* 3종 |
| 3주 | unified/remark로 Markdown AST 다루기 | unifiedjs.com, remark-parse / -frontmatter README |
| 4주 | zod 스키마 검증 + citty CLI 만들기 | zod·citty 공식 문서, packages/cli/src 읽기 |
| 5주 | 모노레포(Bun · Turborepo) + TDD | turbo.build, bun.sh, rules/*.test.ts 분석 |
| 6주 | 프롬프트 설계(prose>tokens) + 에이전트 통합 | PHILOSOPHY.md 정독, spec 명령으로 프롬프트 주입 실험 |
이 레포에 등장하는 주요 용어 한눈에.
| 용어 | 의미 |
|---|---|
| DESIGN.md | 디자인 시스템을 코딩 AI에게 설명하는 파일 포맷이자 그 파일명 |
| design token | 색·폰트·간격 등 디자인 값에 이름을 붙인 최소 단위 |
| front matter | .md 맨 위 --- 사이에 적는 기계용 설정(여기선 YAML 토큰) |
| prose | 토큰 아래 적는 사람용 설명 글 — "왜·언제 쓰는지" |
| normative | '규범값' — 반드시 따라야 하는 값(토큰). prose는 비규범적 맥락 |
| Token Reference | {colors.primary}처럼 값 대신 다른 토큰을 가리키는 참조 |
| Typography 토큰 | fontFamily·fontSize·fontWeight·lineHeight·letterSpacing 등을 담은 객체 |
| DTCG | W3C의 디자인 토큰 표준 JSON 형식(designtokens.org) |
| WCAG 대비 | 글자/배경 명암비 기준. design.md 린터는 AA(4.5:1)로 검사 |
| OKLCH | 사람 눈에 더 자연스러운 최신 CSS 색 표기. 토큰 값으로 허용됨 |
| AST | 텍스트를 의미 단위 트리로 바꾼 자료구조(remark가 생성) |
| unified / remark | Markdown을 AST로 파싱·변환하는 표준 라이브러리 생태계 |
| zod | 데이터가 기대한 모양인지 검사하는 TypeScript 스키마 라이브러리 |
| citty | CLI 서브커맨드를 정의하는 경량 프레임워크 |
| Bun / Turborepo | 빠른 JS 런타임/패키지매니저 · 모노레포 빌드 파이프라인 |
| linter | 파일을 규칙으로 검사해 문제를 짚어주는 도구(여기선 9룰) |
| SSOT | '단일 진실원' — 규칙을 한 곳(spec-config.yaml)에서만 관리 |
원본·공식 문서·관련 표준.