AI 코딩 디자인 — 왜 모든 AI가 똑같은 UI를 만드는가.
Claude Code、Cursor、Windsurf、GitHub Copilot、Cline、Continue 중 하나에 랜딩 페이지를 시켜본 사람이라면 누구나 그 결과를 알아봅니다. 본문용 Inter를 디스플레이 크기로 끌어올린 헤드라인, 보라에서 파랑으로 흐르는 그라데이션, 가로로 나란히 놓인 똑같은 카드 3개, 그리고 히어로 아래의 그 줄 — 「Build something amazing」. 문제는 도구가 아닙니다. 모든 도구가 같은 템플릿 풀에서 학습했다는 게 문제죠. ux-skill은 정확히 그 디폴트들을 CI에서 — LLM 없이, 145개의 결정론적 정규식 규칙으로 — 막아냅니다.
모든 AI가 만들어내는 8가지 시각적 디폴트
전체 분류는 AI 디자인 지문 분류표에 정리해 두었습니다. 거의 모든 히어로 생성물에 등장하는 8가지는 다음과 같습니다.
- 디스플레이용으로 쓰인 Inter — 작은 화면 크기에서의 가독성을 위해 설계된 글자체를 90px 헤드라인까지 끌어올립니다. 본래 용도의 정반대.
- 보라-파랑 그라데이션 —
#7C3AED → #3B82F6계열. 첫 섹션 배경의 단골손님. - 가로로 늘어선 동일 카드 3개 — 아이콘 + 한 단어 제목 + 한 문장 부제, 세 번 반복.
- 모든 요소에 적용된 fade-in-up — 모든 섹션의 모든 직속 자식이 같은 트랜지션을 받음. 역할 구분은 없음.
- 가운데 정렬 일변도 — 히어로, 카드, 폼, 전부 화면 정중앙 축에.
- 일반적인 카피 — 「Build something amazing」「Beautiful experiences」「Revolutionizing X」. 제품 고유 명사는 한 개도 없음.
- 스톡 이미지 URL — 실제 제품 스크린샷이 들어가야 할 자리에 일반 플레이스홀더.
- 플랫 디자인 위 무거운 그림자 — 「눈에 띄게 하자」와 「플랫이 유행이지」가 충돌해 어딘가 어색한 입체감.
개별로 보면 어느 것도 잘못은 아닙니다. 문제는 이 8개가 한 페이지에 동시에 등장할 때 누가 봐도 「이건 AI가 만든 것」이라는 지문이 된다는 점이죠. 하나라면 어깨를 으쓱하고 넘길 수 있습니다. 같은 above-the-fold에 네 개가 모이면 어떤 도구가 만들었는지까지 짚어낼 수 있습니다.
왜 프롬프트만으로는 부족한가
모든 팀의 첫 반응은 프롬프트에 지시를 더하는 것입니다. 「디폴트 그라데이션 쓰지 마」「제대로 된 디스플레이 글자체 골라」「똑같은 카드 3개 늘어놓지 마」. 한 메시지 동안은 통합니다. 다음 메시지에서 지시는 희석되고, 컨텍스트 윈도우는 부풀고, 지문은 돌아옵니다. 프롬프트로 만든 통제는 확률적이고, 대화 길이와 함께 닳습니다.
필요한 건 결정론적 바닥 — 모델이 코드를 쓴 다음에, 루프 안에 또 다른 LLM 없이 도는 점검입니다. ux-skill이 메우는 자리가 정확히 그 빈틈입니다. 추천기가 앞단에서 모델의 선택지를 좁히고, 린터가 뒷단에서 흘러나오는 디폴트를 쳐냅니다.
확률적인 문제에 확률적인 도구를 더 얹지 말 것
「그럼 두 번째 LLM이 첫 번째 LLM의 결과를 채점하면 되지 않나」라는 안은 꾸준히 떠오릅니다. 그러나 LLM 기반 평가는 LLM 기반 생성과 똑같은 분산을 가집니다. 채점 프롬프트, few-shot 예제, 그날 모델 버전에 따라 결과가 흔들립니다. CI에 필요한 건 매번 같은 판정을 돌려주는 층입니다. 그게 정규식의 유일한 강점이고, 그걸로 충분합니다.
145개의 정규식, LLM 호출 없음, CI에서 실행
린터는 *.tsx、*.jsx、*.vue、*.svelte、*.astro、*.css、*.scss、*.html 모든 파일을 스캔합니다. i와 m 플래그를 단 145개의 정규식을 돌리고, 규칙 ID, 심각도, 파일, 행, 열, 발췌, 제안된 수정안을 담은 JSON을 반환합니다.
# 로컬 lint, 기본값은 high+critical 게이트 $ uxskill lint [OK] Scanned 142 files in 412ms · 0 findings at threshold high # 하위 디렉터리 + JSON 출력 $ uxskill lint apps/web/src --json | jq '.summary' { "critical": 0, "high": 4, "medium": 11, "low": 3, "total": 18 }
LLM 호출 0회. 파일 200개짜리 Next.js 저장소의 평균 스캔 시간은 콜드 380ms、웜 90ms입니다. 전체 규칙 명세는 정규식 린터 가이드에 공개되어 있습니다.
실제 히어로에서의 Before / After
아래는 Next.js 스타터에서 잘라낸 단순화된 히어로 블록입니다. 세 규칙에 걸리고, exit 0으로 통과하는 재작성본이 그 아래 있습니다. 전환 의도는 같지만, 지문은 다릅니다.
// Before — high 3건 <section className="bg-gradient-to-br from-purple-500 via-violet-500 to-blue-500 py-32"> <h1 className="font-['Inter'] text-7xl leading-none"> Build something amazing. </h1> <div className="grid grid-cols-3 gap-6"> <Card icon="Zap" title="Fast" /> <Card icon="Shield" title="Safe" /> <Card icon="Heart" title="Loved" /> </div> </section> // After — 0건 <section className="bg-stone-50 py-28"> <h1 className="font-['Fraunces'] text-6xl leading-[1.04] tracking-tight"> 당신의 TMS가 끝내 배포하지 못한 화물 라우팅 계층. </h1> <div className="grid grid-cols-12 gap-6 mt-16"> <Card className="col-span-7" title="화물 통합" /> <Card className="col-span-5" title="운송사 랭킹" /> </div> </section>
Before에서는 세 규칙이 발동합니다. text-7xl로 쓰인 Inter, AI 표준 그라데이션, 동일 카드 3개 그리드. After는 Fraunces(디스플레이)와 Inter(본문)을 짝짓고, 플랫 표면을 채택하며, 7-5 비대칭 그리드로 갈아탔습니다. 의도는 같고 지문은 사라졌습니다.
추천기는 바닥을 올린다. 린터는 천장을 친다. 둘 다 필요하다.
Claude Code 디자인 시스템 셋업
Claude Code는 ux-skill의 홈그라운드입니다. 플러그인 마켓플레이스에서의 설치는 두 줄로 끝납니다.
# Claude Code 플러그인 마켓플레이스
$ /plugin marketplace add Laith0003/ux-skill
$ /plugin install ux@ux-skill
설치하고 나면 Claude Code 세션에 22개의 슬래시 명령이 등록됩니다. /ux-discover는 10개 항목짜리 브리프를 질문 형태로 모으고, /ux-recommend는 5개의 병렬 검색(산업, 스타일, 팔레트, 타이포그래피, 모션)을 돌리며, /ux-persist save는 저장소 루트에 MASTER.md、tokens.css、manifest.json을 씁니다. 이 파일들이 쓰여 있으면 Claude Code는 그 뒤의 모든 세션에서 이를 참고해 코드를 짭니다.
Cursor는 .cursorrules 파일 + MCP 서버 조합, 명령은 uxskill init --target cursor. Windsurf는 .windsurfrules + MCP, uxskill init --target windsurf. GitHub Copilot은 .github/copilot-instructions.md + 디스크 기반 린터, uxskill init --target copilot.
세 가지 설치 경로, 하나의 엔진
같은 Python 패키지가 호환성 매트릭스의 17개 IDE 전부에 닿습니다. 편집기에 가장 가까운 경로를 고르세요:
| 편집기 | 경로 | 명령 |
|---|---|---|
| Claude Code | 마켓플레이스 | /plugin install ux@ux-skill |
| Cursor | .cursorrules + MCP | uxskill init --target cursor |
| Windsurf | .windsurfrules + MCP | uxskill init --target windsurf |
| GitHub Copilot | copilot-instructions.md | uxskill init --target copilot |
| Cline / Continue | MCP 서버 | uxskill mcp-config --target cline |
| JetBrains AI Assistant | .junie/guidelines.md | uxskill init --target jetbrains |
| Zed | MCP stdio | uxskill init --target zed |
| Codex CLI / Aider | 직접 CLI | pip install uxskill |
모든 경로 밑에 깔리는 건 같습니다: 1,182개 카탈로그, 145개 규칙, 160개 브랜드 사양, 22개 명령, 릴리스마다 통과하는 75개 테스트.
규칙은 구조를 잡는다. 취향은 못 잡는다.
린터는 「이 섹션은 리듬이 안 맞아」나 「이 카피는 차갑게 느껴져」를 절대로 잡지 못합니다. 그건 사람의 일이거나, 리뷰 단계의 LLM이 할 일입니다. 정규식이 확실히 잡아내는 건 문자열 토큰, 패턴, 형태로 표현되는 모든 지문입니다. 그게 AI 디폴트의 대부분이죠. 모델은 매번 같은 산출물로 회귀하니까요.
CI에서는 의도적으로 LLM 평가자를 돌리지 않습니다. 기준이 「디자이너가 만든 것 같은가」라면, 그건 코드 리뷰지 lint가 아닙니다. ux-skill에는 그 패스를 위한 ux critique가 따로 있지만, 편집기에서 온디맨드로만 돌고 CI엔 들어가지 않습니다.