$npx -y skills add kwakseongjae/oh-my-design --skill omd-designer-review시각 + 브랜드 일관성 리뷰. HTML/MD/JSX artifact를 받아 brand DESIGN.md 대비 typo hierarchy, 색 budget, radius scale, 컴포넌트 state, 모바일 반응형 검수. severity BLOCK/WARN/FYI + line ref 출력. 'UI 리뷰', '디자인 검토', 'DESIGN.md 대비 검수' 류 트리거.
| 1 | <!-- omd:installed-skill — managed by `omd install-skills`. Do not edit; rerun the command to refresh. --> |
| 2 | |
| 3 | |
| 4 | # omd:designer-review |
| 5 | |
| 6 | artifact를 받아 brand의 DESIGN.md 기준으로 visual / brand consistency를 audit한다. **read-write가 아니라 advisory** — 직접 수정하지 않고 review report만 emit. |
| 7 | |
| 8 | 구조는 [`mastepanoski/claude-skills` ui-design-review](https://agentskills.so/skills/mastepanoski-claude-skills-ui-design-review)에서 차용. |
| 9 | |
| 10 | ## 0. 필수 입력 |
| 11 | |
| 12 | - `artifact_path`: HTML, MD, JSX, TSX 중 하나 |
| 13 | - `design_md_path`: 해당 브랜드의 `references/<id>/DESIGN.md` 또는 프로젝트 루트 `DESIGN.md` |
| 14 | - (선택) `viewport`: `mobile` | `desktop` | `both` (default: both) |
| 15 | |
| 16 | 이 두 입력이 없으면 BLOCK으로 즉시 종료. |
| 17 | |
| 18 | ## 1. Audit 카테고리 (6) |
| 19 | |
| 20 | ### 1.1 Typography hierarchy |
| 21 | |
| 22 | - DESIGN.md `§ Typography` 스펙 read |
| 23 | - artifact 내 h1/h2/h3/p의 size, weight, line-height 추출 |
| 24 | - 일치 여부 검사 |
| 25 | - 빈 h-level skip (h1 → h3) → WARN |
| 26 | - 본문 weight가 400/500이 아닌 700 fall-through → WARN |
| 27 | |
| 28 | ### 1.2 Color budget (Toss "2 saturated brand elements / viewport" rule) |
| 29 | |
| 30 | DESIGN.md `§ Color`의 brand saturated tokens 추출. |
| 31 | |
| 32 | - viewport당 brand saturated 사용 횟수 카운트 |
| 33 | - > 2 → WARN (Toss principle 위반) |
| 34 | - > 4 → BLOCK |
| 35 | - DESIGN.md에 없는 hex 직접 사용 → WARN |
| 36 | - 회색 대신 saturated 사용 (예: warning이 아닌 컨테이너에 red-500) → WARN |
| 37 | |
| 38 | ### 1.3 Radius scale |
| 39 | |
| 40 | - DESIGN.md `§ Radius` 토큰 read (예: 0, 4, 8, 12, 16, 9999) |
| 41 | - artifact 내 `border-radius` 추출 |
| 42 | - 토큰에 없는 값 → WARN |
| 43 | - 한 컴포넌트 안에서 radius 혼용 (8 + 12) → FYI |
| 44 | |
| 45 | ### 1.4 Component states |
| 46 | |
| 47 | 각 interactive 요소가 다음 state를 갖춰야: |
| 48 | - default ✓ |
| 49 | - hover ✓ |
| 50 | - focus (focus-visible OK) ✓ |
| 51 | - active ✓ |
| 52 | - disabled ✓ |
| 53 | |
| 54 | 누락 → BLOCK (focus는 a11y 필수) |
| 55 | |
| 56 | ### 1.5 Mobile responsiveness |
| 57 | |
| 58 | - viewport=both인 경우 mobile에서 검사 |
| 59 | - 최소 hit area 44x44 (iOS HIG) → BLOCK 미달 |
| 60 | - 가로 스크롤 발생 → BLOCK |
| 61 | - 텍스트 14px 미만 → WARN |
| 62 | |
| 63 | ### 1.6 Spacing / layout |
| 64 | |
| 65 | - DESIGN.md `§ Spacing` 토큰 |
| 66 | - 토큰 외 값 (예: `padding: 13px`) → WARN |
| 67 | - 인접 요소 간 일관성 (한 카드 안에서 padding-x가 16 vs 20 혼재) → WARN |
| 68 | |
| 69 | ## 2. Severity 정의 |
| 70 | |
| 71 | | Severity | 의미 | 후속 조치 | |
| 72 | |---|---|---| |
| 73 | | **BLOCK** | a11y 또는 hard rule 위반. 출간 불가. | writer로 revision round 1 | |
| 74 | | **WARN** | best practice 위반. 출간 가능하나 권장 수정. | writer가 판단 후 fix | |
| 75 | | **FYI** | 정보성. 의도일 수 있음. | 무시 가능 | |
| 76 | |
| 77 | ## 3. 출력 형식 |
| 78 | |
| 79 | `<work_dir>/.reviews/designer-review-round-<N>.md`: |
| 80 | |
| 81 | ```markdown |
| 82 | # Designer review — round <N> |
| 83 | |
| 84 | **Date:** <ISO> |
| 85 | **Artifact:** <path> |
| 86 | **DESIGN.md:** <path> |
| 87 | **Viewport:** mobile | desktop | both |
| 88 | |
| 89 | ## Summary |
| 90 | |
| 91 | - BLOCK: <count> |
| 92 | - WARN: <count> |
| 93 | - FYI: <count> |
| 94 | |
| 95 | ## Issues |
| 96 | |
| 97 | ### [BLOCK] Focus state missing on primary CTA |
| 98 | - **Location:** `components/SignupForm.tsx:42` |
| 99 | - **Rule:** § Component states — focus is mandatory |
| 100 | - **Evidence:** `<button className="bg-blue-500 hover:bg-blue-600">` — focus 클래스 없음 |
| 101 | - **Fix suggestion:** add `focus-visible:ring-2 focus-visible:ring-blue-300` |
| 102 | |
| 103 | ### [WARN] Color budget exceeded on mobile hero |
| 104 | - **Location:** `index.ko.md:34-41` |
| 105 | - **Rule:** § Color budget — max 2 saturated / viewport |
| 106 | - **Evidence:** 3 saturated brand 사용 (red-500, blue-500, green-500) |
| 107 | - **Fix suggestion:** green-500을 gray-700 또는 텍스트로 대체 |
| 108 | ... |
| 109 | |
| 110 | ## Verdict |
| 111 | |
| 112 | - **PASS** (BLOCK=0, WARN≤3) — 출간 OK |
| 113 | - **REVISION** (BLOCK=0, WARN>3) — 권장 수정 후 재리뷰 옵션 |
| 114 | - **BLOCK** (BLOCK≥1) — 출간 불가, writer revision round 시작 |
| 115 | ``` |
| 116 | |
| 117 | ## 4. 시각 검수 (optional) |
| 118 | |
| 119 | artifact가 HTML/JSX이고 browser-harness가 가용하면 mobile 320px + desktop 1280px 스크린샷을 캡쳐해 `.reviews/screenshots/`에 저장. 텍스트 audit과 함께 첨부. |
| 120 | |
| 121 | ## 5. DESIGN.md 강제 재독 |
| 122 | |
| 123 | **Anti-pattern**: 이전 review에서 읽은 DESIGN.md를 캐싱해 재사용 → memory hallucination 위험. |
| 124 | |
| 125 | → 매 호출마다 DESIGN.md를 **다시 read**. 읽은 timestamp를 report 헤더에 명시. |
| 126 | |
| 127 | ## 6. Anti-patterns |
| 128 | |
| 129 | - ❌ "looks good" rubber-stamp (final-qa 동일 룰. designer-review도 "전반적으로 괜찮음" 식 응답 금지) |
| 130 | - ❌ DESIGN.md 안 읽고 일반 best practice로 평가 |
| 131 | - ❌ severity inflation (모든 걸 BLOCK) |
| 132 | - ❌ severity deflation (BLOCK 사안을 FYI로) |
| 133 | - ❌ Fix suggestion 없는 issue (반드시 actionable) |
| 134 | - ❌ Line ref 없는 issue (`somewhere in the file` 금지) |
| 135 | |
| 136 | ## 7. 1회 revision 후 재호출 시 |
| 137 | |
| 138 | input에 `prior_report_path` 포함되면: |
| 139 | - 이전 BLOCK/WARN 항목을 list로 추출 |
| 140 | - artifact 재read |
| 141 | - 항목별로 RESOLVED / UNRESOLVED / NEW로 표시 |
| 142 | |
| 143 | Round 2에도 UNRESOLVED BLOCK 있으면 orchestrator로 BLOCK escalation. |
| 144 | |
| 145 | ## 8. 취향 캡처 — review → taste loop (최종 phase) |
| 146 | |
| 147 | review report를 emit한 **후에** 이번 run의 finding들을 한 번 스캔해, 반복 패턴을 취향 후보로 제안한다. report 자체는 advisory 그대로 — 이 phase가 유일하게 쓰기를 일으킬 수 있는 지점이고, 그것도 **사용자가 동의한 경우에만**. |
| 148 | |
| 149 | ### 후보 조건 (둘 중 하나) |
| 150 | |
| 151 | 1. **같은 axis ≥2회** — 이번 run의 finding을 axis로 분류(radius / color / spacing / typo / voice)했을 때 같은 axis가 2회 이상 등장 |
| 152 | 2. **기존 pending preference와 매칭** — `.omd/preferences.md`가 존재하면 read해서, finding이 `status: pending` 엔트리의 scope와 같은 축이면 1회여도 후보 (반복의 증거가 이미 파일에 있으므로) |
| 153 | |
| 154 | `.omd/preferences.md`가 없으면 조건 2는 생략 — 파일을 만들지 않는다. |
| 155 | |
| 156 | ### 제안 (run당 질문 1개 max) |
| 157 | |
| 158 | 후보가 1개 이상이면 **단 한 번** 묻는다: "이 패턴, 취향으로 기록할까요?" |
| 159 | |
| 160 | - **Claude Code**: AskUserQuestion — 후보가 여러 개면 multiSelect 옵션으로 묶어서 한 질문에 (후보당 한 줄: axis + 발생 횟수 + 요약) |
| 161 | - **다른 채널 (Codex / OpenCode)**: 같은 내용을 산문 질문 하나로 |
| 162 | |
| 163 | ### 동의 시 기록 |
| 164 | |
| 165 | 선택된 후보는 **omd:remember 스킬의 기록 절차를 그대로 수행**해 기록한다 — 포맷을 손으로 |