uxskill
Star on GitHub
블로그 · 한국어 · 2026-05-28

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가지는 다음과 같습니다.

  1. 디스플레이용으로 쓰인 Inter — 작은 화면 크기에서의 가독성을 위해 설계된 글자체를 90px 헤드라인까지 끌어올립니다. 본래 용도의 정반대.
  2. 보라-파랑 그라데이션#7C3AED → #3B82F6 계열. 첫 섹션 배경의 단골손님.
  3. 가로로 늘어선 동일 카드 3개 — 아이콘 + 한 단어 제목 + 한 문장 부제, 세 번 반복.
  4. 모든 요소에 적용된 fade-in-up — 모든 섹션의 모든 직속 자식이 같은 트랜지션을 받음. 역할 구분은 없음.
  5. 가운데 정렬 일변도 — 히어로, 카드, 폼, 전부 화면 정중앙 축에.
  6. 일반적인 카피 — 「Build something amazing」「Beautiful experiences」「Revolutionizing X」. 제품 고유 명사는 한 개도 없음.
  7. 스톡 이미지 URL — 실제 제품 스크린샷이 들어가야 할 자리에 일반 플레이스홀더.
  8. 플랫 디자인 위 무거운 그림자 — 「눈에 띄게 하자」와 「플랫이 유행이지」가 충돌해 어딘가 어색한 입체감.

개별로 보면 어느 것도 잘못은 아닙니다. 문제는 이 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 모든 파일을 스캔합니다. im 플래그를 단 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.mdtokens.cssmanifest.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 + MCPuxskill init --target cursor
Windsurf.windsurfrules + MCPuxskill init --target windsurf
GitHub Copilotcopilot-instructions.mduxskill init --target copilot
Cline / ContinueMCP 서버uxskill mcp-config --target cline
JetBrains AI Assistant.junie/guidelines.mduxskill init --target jetbrains
ZedMCP stdiouxskill init --target zed
Codex CLI / Aider직접 CLIpip install uxskill

모든 경로 밑에 깔리는 건 같습니다: 1,182개 카탈로그, 145개 규칙, 160개 브랜드 사양, 22개 명령, 릴리스마다 통과하는 75개 테스트.

정직한 범위

규칙은 구조를 잡는다. 취향은 못 잡는다.

린터는 「이 섹션은 리듬이 안 맞아」나 「이 카피는 차갑게 느껴져」를 절대로 잡지 못합니다. 그건 사람의 일이거나, 리뷰 단계의 LLM이 할 일입니다. 정규식이 확실히 잡아내는 건 문자열 토큰, 패턴, 형태로 표현되는 모든 지문입니다. 그게 AI 디폴트의 대부분이죠. 모델은 매번 같은 산출물로 회귀하니까요.

CI에서는 의도적으로 LLM 평가자를 돌리지 않습니다. 기준이 「디자이너가 만든 것 같은가」라면, 그건 코드 리뷰지 lint가 아닙니다. ux-skill에는 그 패스를 위한 ux critique가 따로 있지만, 편집기에서 온디맨드로만 돌고 CI엔 들어가지 않습니다.

관련 글

설치

17개 IDE. 하나의 엔진. 145개 규칙.

추천기, 린터, MCP 서버, 22개 명령, 160개 브랜드 사양, 1,182개 카탈로그를 한 묶음으로 배포합니다. 린터는 sub-second에 끝나고, 나머지는 온디맨드. MIT, 텔레메트리 없음, 계정 없음.

$ /plugin marketplace add Laith0003/ux-skill
$ /plugin install ux@ux-skill
— 또는 —
$ pip install uxskill
— 또는 —
$ npx uxskill@alpha init