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,243개 카탈로그, 145개 규칙, 160개 브랜드 사양, 22개 명령, 릴리스마다 통과하는 75개 테스트.
규칙은 구조를 잡는다. 취향은 못 잡는다.
린터는 「이 섹션은 리듬이 안 맞아」나 「이 카피는 차갑게 느껴져」를 절대로 잡지 못합니다. 그건 사람의 일이거나, 리뷰 단계의 LLM이 할 일입니다. 정규식이 확실히 잡아내는 건 문자열 토큰, 패턴, 형태로 표현되는 모든 지문입니다. 그게 AI 디폴트의 대부분이죠. 모델은 매번 같은 산출물로 회귀하니까요.
CI에서는 의도적으로 LLM 평가자를 돌리지 않습니다. 기준이 「디자이너가 만든 것 같은가」라면, 그건 코드 리뷰지 lint가 아닙니다. ux-skill에는 그 패스를 위한 ux critique가 따로 있지만, 편집기에서 온디맨드로만 돌고 CI엔 들어가지 않습니다.