
DESIGN.md를 두면 어디까지 '괜찮아질' 수 있을까 — 74건을 측정하여 확인했다
요약
Google Labs가 공개한 DESIGN.md 형식을 통해 AI 기반 UI 생성 시 디자인 의도를 일관되게 유지하는 방법을 분석합니다. 74건의 실험을 통해 색상, 서체, 접근성 등 디자인 시스템의 일관성을 확보하는 효과와 한계를 검증했습니다.
핵심 포인트
- DESIGN.md는 AI가 디자인 의도를 일관되게 이해하도록 돕는 파일 형식임
- 색상, 서체, WCAG 대비비 등 수치적 일관성 유지에 효과적임
- UI 자체를 생성하거나 코드를 직접 검증하는 도구는 아님
- Google Stitch의 내부 포맷을 오픈소스로 공개한 사례임
AI에게 UI를 만들게 하면, 매번 조금씩 다른 결과물이 나옵니다.
"모던하고, 깔끔하며, 신뢰감 있는 느낌으로"라고 요청합니다. 나쁘지 않은 결과물이 나옵니다. 다음 날 다시 요청합니다. 또 나쁘지 않은 결과물이 나옵니다. 하지만 어제와는 다릅니다.
Google Labs가 공개한 DESIGN.md는 이 "매번 달라지는 현상"을 멈추기 위한 파일 형식입니다. 디자인 의도를 파일 하나에 작성하여, AI가 매번 읽게 합니다.
실제로 도입했을 때 어디까지 효과가 있는지 측정했습니다. 결론부터 말씀드리겠습니다.
이 기사의 내용
| 효과가 있는 부분과 없는 부분 | 먼저 결론부터 |
| 이 파일이 도대체 무엇인지 | 출처와 Google 자체의 설명 |
| 실제 사례 74건을 측정했다 | 작성법은 두 가지로 나뉜다 / 공식 샘플은 따라 하지 않는 것이 좋다 |
| ... |
조사한 내용은 리포지토리에 정리되어 있습니다
기사에 작성한 숫자와 실험은 모두 여기서 재현할 수 있습니다.
| 구조 레퍼런스 | 스키마·타입·섹션 사전 |
| 두 가지 작성법과 선택 방법 | 74건의 측정 결과와 측정 스크립트 |
| 작성 가이드 | 좋은 예·나쁜 예·리뷰 관점 |
| ... |
디자이너를 위해 수치(value) 이야기를 제외한 해설도 마련해 두었습니다 → Wiki
효과가 있는 부분과 없는 부분
효과가 있는 부분
- 색상이나 서체 지시가 흔들리지 않는다. 세션이 바뀌어도, 담당자가 바뀌어도 동일한 값이 나온다.
- WCAG의 대비비(contrast ratio)를 기계적으로 체크할 수 있다.
- Tailwind 설정이나 CSS 변수로 추출할 수 있다.
- 값이 결정되지 않은 단계에서도 작성을 시작할 수 있다.
효과가 없는 부분
- UI를 생성하지 않습니다. CLI에 있는 것은 검증과 변환뿐입니다.
- 당신의 코드는 한 줄도 읽지 않습니다. ESLint와 달리, 검사 대상은 DESIGN.md 자신입니다.
- 문장 부분은 검증되지 않습니다. 11개의 검사 규칙 중 Markdown 본문을 보는 것은 1개뿐이며, 그마저도 헤딩(heading)의 순서만 확인합니다.
- 버튼 하나를 다 써내지 못합니다 (후술).
가장 명확하게 말할 수 있는 것은 이것입니다.
DESIGN.md를 두더라도, 구현이 그것을 따르고 있는지는 아무도 확인하지 않습니다.
lint는 통과합니다. CI도 초록색이 됩니다. 하지만 그것은 "DESIGN.md라는 파일의 형식이 올바르다"는 의미일 뿐, 화면이 의도대로인지와는 무관합니다.
이 파일이 도대체 무엇인지
YAML의 front matter에 색상이나 서체의 값을 작성하고, 그 아래 Markdown에 "왜 그 값인지"를 작성합니다.
---
name: Heritage
colors:
...
Stitch에서 나온 것
출처를 파악해 두면 이후의 이야기가 연결됩니다.
GitHub 리포지토리의 homepage가 Google Stitch의 문서를 가리키고 있습니다.
$ gh repo view google-labs-code/design.md --json homepageUrl
{"homepageUrl":"https://stitch.withgoogle.com/docs/design-md/specification"}
공식 블로그(2026-04-21)의 제목이 바로 답입니다.
Stitch's DESIGN.md format is now open-source so you can use it across platforms.
Stitch는 Google Labs의 UI 생성 도구입니다. 그곳에서 사용하던 내부 포맷을 다른 도구에서도 사용할 수 있도록 분리해낸 것입니다.
Google은 무엇이라고 말하는가
이 부분은 정확하게 인용하겠습니다.
AI agents can know exactly what a color is for, and can
validate their choices against WCAG accessibility rules.
검증할 수 있는 대상으로 이름이 올라온 것은 WCAG뿐입니다. "디자인으로서 올바른지 검증할 수 있다"라고는 쓰여 있지 않습니다.
그리고 실제로 도구는 그대로 작동합니다. Google의 설명은 정확합니다. 어긋나는 지점은, 읽는 쪽에서 "그럼 디자인도 지켜지겠구나"라고 범위를 넓게 해석해 버리는 부분입니다.
실제 사례 74건을 측정했다
사양서를 읽어도 "그래서 다들 어떻게 쓰고 있는 거지"는 알 수 없습니다. 그래서 측정했습니다.
대상은 awesome-design-md라는 자원봉사자들의 컬렉션입니다. airbnb, apple, figma, nike, notion, spotify, tesla 등 74건이 포함되어 있습니다 (공식적인 것이 아니라 커뮤니티 제작물입니다).
측정 스크립트를 공개하고 있으므로, 동일한 결과를 낼 수 있습니다.
git clone --depth 1 https://github.com/VoltAgent/awesome-design-md.git /tmp/awesome
python3 tools/measure.py /tmp/awesome/design-md
작성 방식은 두 가지로 나뉩니다
| 건수 | 내용 | |
|---|---|---|
| 색상이나 서체 값을 적고 있는 것 | 64 | Overview Colors Typography … 사양대로의 헤딩 |
| 값을 하나도 적지 않고, 문장으로만 된 것 | 10 | 1. Visual Theme & Atmosphere 〜 9. Agent Prompt Guide 식의 번호 매기기 |
후자 10건은 색상 코드(color code)가 단 하나도 나오지 않습니다. 전부 설명문입니다 (starbucks는 450행).
둘 다 lint를 통과합니다. 값이 확정되지 않은 단계라면, 문장만으로 시작해도 문제없습니다.
내역과 분포는 '두 가지 작성 방식과 선택 방법'에 모두 실려 있습니다.
공식 샘플은 따라 하지 않는 편이 좋다
동일한 잣대로, 원본에 동봉된 샘플 3건도 측정했습니다.
| 값의 행수 (중앙값) | 문장의 행수 (중앙값) | |
|---|---|---|
| 실제 사례 64건 | 268 | 206 |
| 공식 샘플 3건 | 144 | 37 |
문장의 양이 5.6배 차이 납니다. 게다가 실제 사례의 최댓값과 공식 샘플의 최솟값이 겹치지 않습니다. 공식 샘플은 실제 사례의 분포 밖에 있습니다.
이유는 샘플의 내용을 보면 짐작할 수 있습니다. 3건 모두 색상 수가 정확히 47개로 일치하며, 명명 규칙(naming)도 surface-container-lowest, on-primary-fixed-variant와 같이 Material Design 3 그 자체입니다. 테마 생성 도구의 출력을 그대로 가져다 놓은 것처럼 보입니다.
본보기로 삼아야 할 것은 공식 샘플이 아니라, 실제 사례의 중앙값입니다.
사양에 없는 헤딩이 정착되어 있다
정식 8개 섹션에 포함되지 않았음에도, 과반수가 사용하고 있는 헤딩이 3개 있었습니다.
| 헤딩 | 사용률 | 내용 |
|---|---|---|
| Responsive Behavior | 51 / 64 | 화면 너비별 동작 |
| ... |
뒤의 2개는 사양에서 상정하지 않은 것입니다.
Known Gaps는 적어두면 효과적입니다. "아이콘은 미정. 기존 선의 굵기로부터 추측해도 좋다"와 같이 적는 것입니다. 적어두지 않으면 AI가 마음대로 채워 넣으며, 심지어 매번 다른 방식으로 채워 넣습니다.
사양대로 적으면 망가지는 부분
npm으로 공개되어 있는 @google/design.md@0.4.0에서 확인한 내용입니다. 7건을 발견했지만, 에러가 발생하는 것은 1건뿐이며, 나머지는 조용히 망가집니다.
대표적인 것을 4가지 꼽겠습니다. 나머지 3건과 CI에 넣을 체크 예시는 '함정'에 있습니다.
수치를 그대로 적으면 사라진다
사양서에는 lineHeight를 "단위 없는 수치도 가능"하다고 적고 있으며, 사양서 자체의 샘플도 lineHeight: 1.1을 사용하고 있습니다.
하지만 YAML의 수치(number)로 적으면 버려집니다. 문자열(string)로 적으면 통과합니다.
typography:
body:
lineHeight: 1.5 # 사라짐
...
$ npx @google/design.md@0.4.0 export --format css-tailwind P.md
@theme {
--leading-body2: 1.5; ← body2만 남음. body는 사라짐
...
게다가 건수 요약(summary)은 사라진 후의 수를 보고하기 때문에, 알아챌 수 있는 수단이 없습니다.
대책: front matter의 값은 전부 따옴표로 감싼다.
참조가 깨져 있어도 조용히 사라진다
broken-ref라는 규칙은 "해결되지 않는 참조는 에러"라고 설명되어 있지만, 실제로는 components 섹션만 확인하고 있습니다.
colors:
primary: "#1A1C1E"
accent: "{colors.nope}" # 존재하지 않는 참조
lint는 경고를 내지 않습니다. export 하면 accent
가 통째로 사라집니다.
대책: {참조}
는 components
안에서만 사용한다.
깨진 CSS가 발생함
colors:
bad: "hsl(120 100% 50% / -1)"
--color-bad: #00ff00-ff; ← CSS로서 구문 오류 (syntax error)
이것이 테마 파일에 섞이면, 해당 선언 자체가 무효화됩니다. 빌드는 통과하지만, 실행 시점에 색상이 적용되지 않는 방식으로 망가집니다.
대책: 색상은 #RRGGBB
로 작성한다. 사양(specification)에서도 호환성 이유로 hex를 권장하고 있습니다.
중복 헤더는 에러가 되지 않음
사양서에는 "중복되는 섹션 헤더는 에러로 처리하여 파일을 거부한다"라고 적혀 있지만, 구현되어 있지 않습니다.
대책: 직접 체크 로직을 추가한다.
grep -E '^## ' DESIGN.md | sort | uniq -d
버튼 1개조차 다 적지 못함
이 부분이 가장 명확한 한계입니다.
일반적인 버튼의 CSS를 나열해 보겠습니다.
.btn {
display: inline-flex; align-items: center; justify-content: center;
gap: 6px; height: 34px; padding: 0 16px;
...
}
DESIGN.md에 컴포넌트로서 작성할 수 있는 것은 이 8가지뿐입니다.
backgroundColor
textColor
typography
rounded
padding
size
height
width
(타입과 섹션 목록은 구조 레퍼런스(structure reference)에 정리했습니다)
| 버튼이 가지고 있는 것 | 작성 가능 여부 |
|---|---|
| height, font-size, font-weight, border-radius | 작성 가능 |
padding 0 16px | 2개 값(2-value)이므로 사양 범위 밖 |
| gap | 작성 불가능 |
| border | 작성 불가능 |
| transition | 작성 불가능 |
| display, align-items, justify-content | 작성 불가능 |
버튼 1개조차 이 정도입니다. 카드, 테이블, 얼러트(alert), 폼(form) 등으로 늘려가다 보면, 작성할 수 없는 것이 더 많아집니다.
따라서 "디자이너가 DESIGN.md를 수정하면 구현된 모습이 바뀐다"라는 기대는, 사양의 능력으로서 성립하지 않습니다. 문장으로 "높이는 34px로 해줘"라고 쓸 수는 있지만, 쓰는 것만으로는 아무 일도 일어나지 않습니다.
어떻게 작성할 것인가
측정 결과로부터 알 수 있는 점을 정리합니다.
1. 값이 결정되지 않았다면, 문장으로만 시작한다
74건 중 10건은 색상 코드(color code)를 단 하나도 적지 않았습니다. 결정되지 않은 값을 먼저 채워 넣으면, 근거 없는 숫자가 고착화됩니다.
2. Overview에 구체적인 참조를 하나 둔다
"모던하고 깔끔한"은 범위가 너무 넓어서, AI는 그 중간 어디쯤의 무난한 것을 만듭니다. "역의 전광판", "미술관 도록", "의료 기기 조작 패널"처럼 구체적인 사물을 예로 들면, 거기서부터 세부 사항이 결정됩니다.
게다가 여기에는 부수적인 효과가 있습니다. 구체적인 사물을 예로 들면, 해서는 안 될 일이 자동으로 따라옵니다. "강의 유인물"이라고 하면, 그라데이션(gradient)이나 글로우(glow) 효과를 사용하지 않는다는 것이 전달됩니다. 쓰지 않아도 전달되는 것입니다.
3. Don't가 늘어나기 시작하면, Overview로 돌아간다
본래의 PHILOSOPHY.md에는 이렇게 적혀 있습니다 (번역은 필자).
A long rambling list is often a sign the description was too vague to carry them.
(길고 두서없는 리스트는, 설명이 너무 모호하여 그것들을 담아내지 못했다는 징후인 경우가 많다)
금지 사항을 추가하고 싶어지면, 먼저 참조를 구체화하는 것이 더 빠르게 해결됩니다.
4. Known Gaps를 작성한다
"결정되지 않음"이라고 적는 것만으로도, AI가 멋대로 채워 넣는 것을 방지할 수 있습니다. "미정"과 "의도적으로 가지지 않음"은 구분해서 적습니다.
5. 두 가지 함정만 피한다
값은 모두 따옴표로 감싼다. {참조}
는 components
내에서만 사용합니다. 이렇게 하면 「말없이 사라지는 (silent disappearance)」 현상의 대부분을 방지할 수 있습니다.
작성 방법의 상세 내용은 작성 가이드(Writing Guide)에, 그대로 사용할 수 있는 시작점은 템플릿(Template)에 마련되어 있습니다. 함정을 피할 수 있는 방식으로 작성되어 있으므로, 복사하기만 하면 5번 규칙은 자동으로 충족됩니다.
팀 내에 CSS를 작성할 수 있는 사람이 없는 경우에는 시작 방법이 달라집니다 → 디자이너가 없는 조직에서의 운영
준수 여부를 어떻게 확인할 것인가
여기서부터가 본론입니다. DESIGN.md는 구현(Implementation)을 보지 않기 때문에, 확인하는 메커니즘은 직접 만들어야 합니다. 만들 수 있는지 실험해 보았습니다.
아래는 요점입니다. 실험 환경·스크린샷·판정 스크립트는 검증 실험(Verification Experiment)에 있습니다.
수행한 작업
「미술관 도록」을 참조하여 DESIGN.md를 작성하고, 지켜야 할 규칙 5가지를 정했습니다.
| 규칙 | |
|---|---|
| V1 | 강조 색상(Accent color)을 글자에 사용하지 않음 (버튼 배경만 허용) |
| ... |
동일한 카드 UI를 3가지 버전으로 구현했습니다. 차이점은 위반 사항뿐입니다.
A: 위반 없음 -
B: 5가지 모두 위반 -
C: V2와 V4만 위반
이를 두 가지 방법으로 판정하게 했습니다.
CSS를 읽는 판정: Playwright를 사용하여 계산된 스타일(Computed style)을 스캔함 -
이미지를 보는 판정: 스크린샷만을 LLM에 전달함
LLM에는 정답을 숨겼습니다. 파일명을 sample-1/2/3으로 지정하고, 순서도 뒤섞었으며, 이미지에 새겨진 라벨도 지웠습니다. 그리고 선택지에 **undetermined (이미지로는 판단할 수 없음)**를 준비하여, "모르는 것을 단정 짓는 것보다 모른다고 말하는 것이 덜 해롭다"라고 명시했습니다.
도중에 실험이 망가졌다
스크린샷을 찍은 시점에서, A(font-weight 600)와 C(800)의 타이틀이 육안으로는 거의 동일했습니다.
Georgia 서체에는 600과 800이 없기 때문에, 브라우저가 둘 다 합성 볼드(Synthetic bold)로 그립니다. CSS 상으로는 명확한 위반이지만, 이미지에는 차이가 나타나지 않습니다.
여기서 알게 된 사실이 있습니다.
규칙에는 "CSS를 보지 않으면 알 수 없는 것"과 "이미지를 보지 않으면 알 수 없는 것"이 있다. 판정을 한 종류로만 제한하면 반드시 놓치는 부분이 생긴다.
결과
CSS를 읽는 판정은 완벽했습니다.
A(위반 없음) : 0건
B(5가지 위반) : V1~V5 전부 검출
C(2가지 위반) : V2와 V4만
오탐(False positive) 없음, 미검출(False negative) 없음, LLM 미사용.
이미지를 보는 판정 역시, 판정 가능한 범위 내에서는 모두 정답이었습니다.
| sample-1 = C | sample-2 = A | sample-3 = B | |
|---|---|---|---|
| V1 강조 색상 | ok | ok | 위반 |
| V2 font-weight | undetermined | undetermined | undetermined |
| V3 모서리 곡률 (Corner radius) | ok | ok | 위반 |
| V4 그림자 (Shadow) | 위반 | ok | 위반 |
| V5 그라데이션 (Gradient) | ok | ok | 위반 |
판정 가능한 12개 항목 모두 정답이었습니다. 위반이 없는 A를 단 한 건도 위반이라고 하지 않았습니다.
그리고 V2는 3장 모두 "모르겠다"라고 답했습니다. 이유 설명이 정확했습니다 (이하는 요약).
래스터 이미지(Raster image)에는 폰트 웨이트(Font weight)의 수치 정보가 담기지 않는다. 대리 지표로는 스템 폭(Stem width)뿐이지만, 600과 700의 경계는 스템 폭에서 불과 몇 % 차이뿐이며, 그 경계 위치는 서체의 웨이트 축(Weight axis)에 의존한다. 서체를 식별할 수 없는 이상, 600인지 700인지 할당하는 것은 추측에 불과하다.
나아가, 우리가 육안으로 세운 가설을 실측으로 입증해 냈습니다. 헤드라인의 잉크 픽셀 수를 세어 다음과 같이 보고했습니다.
15661 / 15661 / 15507
순서대로 sample-1 / 2 / 3입니다. sample-1은 font-weight 800, sample-2는 600임에도 불구하고, 픽셀 수가 일치합니다. 이미지상에 차이가 존재하지 않음이 수치로 확정되었습니다.
알게 된 점
판정을 3개 층으로 나누는 것이 정답이었습니다.
이미지를 보는 판정 … 여백의 인상, 전체적인 분위기 ← LLM
CSS를 읽는 판정 … 수치로 작성된 규칙 ← 이 부분이 비어 있음
lint … DESIGN.md 자체의 서식 ← 기존 방식
CSS에서 알 수 있는 것을 LLM에게 물어봐서는 안 됩니다. 정확도가 떨어질 뿐만 아니라 비용도 많이 듭니다. LLM이 나설 자리는 CSS에 적혀 있지 않은 것뿐입니다.
"모르겠다"라고 말할 수 있었던 것은 그렇게 만들었기 때문입니다
LLM이 솔직하게 대답한 것은 모델이 똑똑했기 때문이 아닙니다.
undetermined라는 선택지를 마련했다 - 기권을 권장한다고 명시했다- "이미지의 어느 부분을 보고 그렇게 판단했는가"를 필수 항목으로 만들었다
- 정답을 추측할 수 있는 정보를 전부 삭제했다
어느 하나라도 제외했다면 결과는 달라졌을 것입니다. 특히 첫 번째 항목이 결정적인데, "위반"인지 "ok"인지의 이지선다만 제공한다면 V2에 대해서도 반드시 둘 중 하나를 대답합니다. 그리고 그것은 근거 없는 추측이 됩니다.
가장 위험한 것은 초록색(Pass)으로 표시되는 것
지금까지 언급한 것들을 나열하면 모두 같은 형태를 띠고 있습니다.
| 외관 | 실제 |
|---|---|
| 수치가 사라짐 | lint 성공, exit 0 |
| ... |
모두 에러가 발생하지 않습니다. CI는 초록색입니다.
반면, 실험에서 LLM이 반환한 undetermined는 반대의 성질을 가집니다. "V2는 판정할 수 없습니다"라는 말을 들은 사람은 다른 수단을 마련하겠지만, "V2는 ok입니다"라는 말을 들은 사람은 아무것도 하지 않습니다. 후자의 경우가 사용자 경험은 더 매끄럽지만, 결과물은 망가집니다.
커버리지(Coverage)도 같은 형태를 띠고 있습니다
직접 제안해 놓고 말하기 조심스럽지만, "DESIGN.md에 작성한 컴포넌트가 전부 Storybook에 있는가"라는 체크는 만들 수 있습니다. 만들 수 있고 유용하기도 합니다.
하지만 커버리지 100%가 그 전부가 의도대로임을 의미하지는 않습니다. 전부 DESIGN.md와 정반대이더라도 초록색이 됩니다.
망라(Exhaustive)하는 것과 올바른 것은 별개입니다. "테스트를 도입했다", "커버리지를 높였다"로 안심하는 구조는 위의 표와 완전히 같은 형태를 하고 있습니다.
경로(Path)로 생각하기
한 단계 더 확장하면 다음과 같습니다.
DESIGN.md ──→ 토큰(Token) ──→ 테마(Theme) ──→ 화면(Screen)
✕ ✕ ✕
문장은 검증되지 않음 / 구현을 보지 않음 / 참조되고 있는지 불명```
**각 공정은 개별적으로 올바르고, 각각의 CI도 초록색이지만, 그럼에도 끝에서 끝까지는 연결되어 있지 않습니다.** 그리고 경로 전체를 보는 사람이 구조상 어디에도 없습니다. 공정마다 담당자는 있어도, "DESIGN.md에 적은 내용이 화면에 전달되고 있는가"를 보는 역할은 누구에게도 할당되어 있지 않기 때문입니다.
### 자신의 repo에서 측정할 수 있는 3가지 숫자
추상론으로 끝내지 않기 위해, 지금 측정할 수 있는 것들을 나열합니다.
1. 테마를 참조하고 있는 파일의 비율
grep -rl "your-theme-package" src --include='.tsx' | wc -l
find src -name '.tsx' | wc -l
...
**1이 낮고 2가 높다면, 토큰을 수정해도 화면은 변하지 않습니다.** 그 상태에서 디자인 정의를 정비해도 성과는 나오지 않습니다. 3은 대개 0입니다.
## 사람에게 무엇을 물을 것인가
마지막으로 하나 더. 실험에서 LLM에게 "모르겠다"라고 말하게 했던 것과 같은 이야기가 인간 측에도 있습니다.
"이 구현이 규약에 부합하는가"를 물으려면, 규약을 이해하고 있어야 합니다.
"**이 두 장은 같은가, 다른가**"라면 누구나 대답할 수 있습니다.
같은 것을 확인하는 데에도 질문 방식에 따라 필요한 숙련도가 달라집니다. 대답할 수 없는 형태로 질문하면 돌아오는 것은 추측입니다. 이는 기계든 인간이든 마찬가지입니다.
그러므로 확인 메커니즘을 만든다면, **사람에게 남기는 판단은 훈련이 필요 없는 것으로 만드는 것**이 좋다고 생각합니다. 차이가 발생한 뒤의 "왜"는 기계와 AI에게 맡길 수 있습니다.
## 요약
- DESIGN.md는 Google Stitch에서 분리된 것으로, 2026-04-21에 Apache 2.0 라이선스로 공개된 draft (초안) 사양입니다.
- Google의 설명은 정확하고 절제되어 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기