+ 요구된 8개 섹션과 토큰 매핑을 충실히 구현했다.
- Slot 링크에 disabled를 전달하는 코드와 일부 미정 토큰이 문제다.
토큰 시스템, 컴포넌트명, 프레임워크를 넣으면 AI 코딩 도구가 따를 수 있는 CLAUDE.md용 컴포넌트 명세를 Markdown으로 작성합니다.
| 분류 | 개발 › 기술 문서 |
|---|---|
| 태그 | 초안작성개발자코드템플릿 |
You are a design systems documentarian creating the component specification
for a CLAUDE.md file. This documentation will be used by AI coding assistants
(Claude, Cursor, Copilot) to generate consistent UI code.
## Context
- **Token system:** [Paste or reference Phase 2 output]
- **Component to document:** [Component name, or "all components from inventory"]
- **Framework:** [Next.js + React + Tailwind / etc.]
## For Each Component, Document:
### 1. Overview
- Component name (PascalCase)
- One-line description
- Category (Navigation / Input / Feedback / Layout / Data Display)
### 2. Anatomy
- List every visual part (e.g., Button = container + label + icon-left + icon-right)
- Which parts are optional vs required
- Nesting rules (what can/cannot go inside this component)
### 3. Props Specification
For each prop:
- Name, type, default value, required/optional
- Allowed values (if enum)
- Brief description of what it controls visually
- Example usage
### 4. Visual Variants
- Size variants with exact token values (padding, font-size, height)
- Color variants with exact token references
- State variants: default, hover, active, focus, disabled, loading, error
- For EACH state: specify which tokens change and to what values
### 5. Token Consumption Map
Component: Button
├── background → button-bg-${variant} → color-brand-${shade}
├── text-color → button-text-${variant} → color-white
├── padding-x → button-padding-x-${size} → spacing-{n}
├── padding-y → button-padding-y-${size} → spacing-{n}
├── border-radius → button-radius → radius-md
├── font-size → button-font-${size} → font-size-{n}
├── font-weight → button-font-weight → font-weight-semibold
└── transition → motion-duration-fast + motion-ease-default
### 6. Usage Guidelines
- When to use (and when NOT to use — suggest alternatives)
- Maximum instances per viewport (e.g., "only 1 primary CTA per section")
- Content guidelines (label length, capitalization, icon usage)
### 7. Accessibility
- Required ARIA attributes
- Keyboard interaction pattern
- Focus management rules
- Screen reader behavior
- Minimum contrast ratios met by default tokens
### 8. Code Example
Provide a copy-paste-ready code example using the actual codebase's
patterns (import paths, className conventions, etc.)
## Output Format
Markdown, structured with headers per section. This will be directly
inserted into the CLAUDE.md file.디자인 시스템 컴포넌트의 사용 규칙과 구현 예시를 문서화할 때 좋다. 구조, props, 상태별 토큰, 접근성, 코드 예시를 실제 코드베이스 패턴에 맞춰 요구한다.
ChatGPT가 가장 완전하고 입력 토큰에도 충실하다. Gemini는 구성은 좋지만 부정확하고 미완성이며, [C]는 제출되지 않았다.
+ 요구된 8개 섹션과 토큰 매핑을 충실히 구현했다.
- Slot 링크에 disabled를 전달하는 코드와 일부 미정 토큰이 문제다.
+ 표와 상태 매트릭스로 세부 규칙을 찾기 쉽게 구성했다.
- 코드가 중간에 끊겼고 없는 색상 토큰과 잘못된 대비값을 만들었다.
| 기준 | ChatGPT | Gemini | 앞선 모델 |
|---|---|---|---|
| 지시 준수 | 9 | 5 | ChatGPT +80% |
| 정확성 | 8 | 5 | ChatGPT +60% |
| 구체성 | 9 | 7 | ChatGPT +29% |
| 구성·가독성 | 9 | 8 | ChatGPT +13% |
| 분량 적정성 | 8 | 4 | ChatGPT +100% |
gpt-5.6-sol가 모델 이름을 가린 채 1~10점으로 채점했습니다 (2026-09-24). 측정값이 아니라 AI 심사 결과입니다.
같은 입력을 세 모델에 넣어 받은 답을 그대로 옮겼습니다. 각 CLI(에이전트 하네스)에서 실행했습니다. ChatGPT·Claude 앱이나 웹에서는 답이 다를 수 있습니다.
[붙여 넣은 자료] Token system (Phase 2 산출물): - color-brand-500: #2563EB, color-brand-600: #1D4ED8 - spacing-1~8: 4px 단위로 4px~32px - radius-md: 8px, radius-lg: 12px - font-size-sm/base/lg: 14px/16px/18px Component to document: Button Framework: Next.js 14 + React + TailwindCSS (shadcn/ui 기반)
Button기본 프레임워크는 Next.js 14, React, TailwindCSS, shadcn/ui의 cva 및 Slot 패턴을 따른다.
Button
├── interactive container
├── icon-left optional
├── label required, icon-only일 때는 visually hidden 가능
├── icon-right optional
└── loading indicator optional
aria-label 또는 sr-only 접근성 이름<button>, <a>, 입력 필드 또는 인터랙티브 요소를 중첩하지 않는다.Button보다 Link를 사용한다.asChild 사용 시 단일 React element만 자식으로 전달한다.| Prop | Type | Default | Required | 설명 |
|---|---|---|---|---|
variant |
"default" | "outline" | "ghost" | "destructive" |
"default" |
Optional | 버튼의 색상 및 시각적 강조 수준 |
size |
"sm" | "default" | "lg" | "icon" |
"default" |
Optional | 버튼의 높이, 패딩, 글자 크기 |
asChild |
boolean |
false |
Optional | 자식 요소의 태그와 동작을 유지하면서 Button 스타일을 적용 |
loading |
boolean |
false |
Optional | 로딩 상태 표시 및 중복 클릭 방지 |
disabled |
boolean |
false |
Optional | 버튼 비활성화 |
className |
string |
undefined |
Optional | 추가 Tailwind 클래스 |
children |
React.ReactNode |
— | Required | 버튼 내용 |
type |
"button" | "submit" | "reset" |
"button" |
Optional | 폼 내 버튼의 동작 |
aria-label |
string |
undefined |
Conditional | 아이콘 전용 버튼의 접근성 이름 |
<Button variant="default" size="default">
저장
</Button>
<Button variant="outline" loading>
저장 중
</Button>
<Button size="icon" aria-label="설정 열기">
<Settings className="size-4" />
</Button>
<Button asChild>
<Link href="/settings">설정</Link>
</Button>
| Size | Height | Padding X | Padding Y | Font size | 아이콘 |
|---|---|---|---|---|---|
sm |
32px | spacing-3 = 12px |
spacing-2 = 8px |
font-size-sm = 14px |
16px |
default |
40px | spacing-4 = 16px |
spacing-2 = 8px |
font-size-base = 16px |
16px |
lg |
48px | spacing-6 = 24px |
spacing-3 = 12px |
font-size-lg = 18px |
20px |
icon |
40px | 0px | 0px | — | 16px |
border-radius: radius-md = 8pxfont-weight: font-weight-semibold = 600gap: spacing-2 = 8pxtransition: motion-duration-fast + motion-ease-default| Variant | Default | Hover | Active | Text |
|---|---|---|---|---|
default |
color-brand-500 = #2563EB |
color-brand-600 = #1D4ED8 |
color-brand-600 = #1D4ED8 |
color-white |
outline |
transparent + color-brand-500 border |
color-brand-500 background |
color-brand-600 background |
color-brand-600 |
ghost |
transparent | color-brand-500 at 10% opacity |
color-brand-500 at 15% opacity |
color-brand-600 |
destructive |
color-error-500 |
color-error-600 |
color-error-600 |
color-white |
destructive와 ghost에 필요한 color-error-*, 투명도 토큰은 Phase 2 토큰 시스템에 추가하거나 프로젝트의 기존 semantic token으로 매핑한다.
| State | 변경 토큰 |
|---|---|
| Default | button-bg-{variant}, button-text-{variant}, button-radius, size별 padding/font |
| Hover | 배경을 color-brand-600으로 변경. outline은 color-brand-500 배경으로 변경 |
| Active | 배경을 color-brand-600으로 변경하고 transform: translateY(1px) 적용 가능 |
| Focus-visible | ring-width-2, ring-color-brand-500, ring-offset-2 적용 |
| Disabled | opacity-50, cursor-not-allowed, hover/active 스타일 제거 |
| Loading | 기존 label의 시각적 투명도 감소, loading-indicator 표시, 클릭 방지 |
| Error | color-error-* border/background/text 및 aria-invalid="true" 적용 |
로딩 상태에서는 disabled와 동일하게 키보드 및 포인터 입력을 차단한다.
Button
├── background
│ └── button-bg-${variant}
│ ├── default → color-brand-500
│ └── hover/active → color-brand-600
├── text-color
│ └── button-text-${variant}
│ ├── default → color-white
│ └── outline/ghost → color-brand-600
├── border-color
│ └── button-border-${variant}
│ └── outline → color-brand-500
├── padding-x
│ └── button-padding-x-${size}
│ ├── sm → spacing-3
│ ├── default → spacing-4
│ └── lg → spacing-6
├── padding-y
│ └── button-padding-y-${size}
│ ├── sm/default → spacing-2
│ └── lg → spacing-3
├── height
│ ├── sm → 32px
│ ├── default/icon → 40px
│ └── lg → 48px
├── border-radius
│ └── button-radius → radius-md
├── font-size
│ ├── sm → font-size-sm
│ ├── default → font-size-base
│ └── lg → font-size-lg
├── font-weight
│ └── button-font-weight → font-weight-semibold
├── icon-size
│ ├── sm/default → 16px
│ └── lg → 20px
└── transition
└── motion-duration-fast + motion-ease-default
Link 사용Select, RadioGroup, Tabs 사용DropdownMenuTrigger 사용default 스타일의 Primary CTA를 최대 1개만 둔다.저장, 계속, 초대 보내기aria-label을 제공한다.<button>을 사용하므로 별도의 role="button"을 추가하지 않는다.aria-label을 필수로 제공한다.aria-busy="true"를 제공한다.aria-invalid="true"를 제공할 수 있다.aria-expanded 및 aria-controls를 사용한다.disabled 속성을 우선 사용한다.Tab: 버튼으로 이동Enter 또는 Space: 버튼 실행Shift + Tab: 이전 포커스 가능 요소로 이동asChild로 링크를 렌더링하는 경우 링크의 기본 키보드 동작을 유지한다.:focus-visible에서만 focus ring을 표시한다.ring-width-2, ring-color-brand-500, ring-offset-2를 사용한다.aria-hidden="true"를 설정하고 버튼에 aria-label을 지정한다.저장 → 저장 중.color-brand-500(#2563EB) + color-white: 약 5.17:1color-brand-600(#1D4ED8) + color-white: 약 6.70:1프로젝트의 일반적인 shadcn/ui 구조에서는 @/components/ui/button 경로를 사용한다.
// components/ui/button.tsx
"use client"
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { Loader2 } from "lucide-react"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
[
"inline-flex items-center justify-center gap-2 whitespace-nowrap",
"rounded-[8px] text-center font-semibold",
"transition-colors duration-150 ease-out",
"focus-visible:outline-none focus-visible:ring-2",
"focus-visible:ring-[#2563EB] focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
],
{
variants: {
variant: {
default:
"bg-[#2563EB] text-white hover:bg-[#1D4ED8] active:bg-[#1D4ED8]",
outline:
"border border-[#2563EB] bg-transparent text-[#1D4ED8] hover:bg-[#2563EB] hover:text-white",
ghost:
"bg-transparent text-[#1D4ED8] hover:bg-[#2563EB]/10 active:bg-[#2563EB]/15",
destructive:
"bg-error-500 text-white hover:bg-error-600 active:bg-error-600",
},
size: {
sm: "h-8 px-3 py-2 text-sm [&_svg]:size-4",
default: "h-10 px-4 py-2 text-base [&_svg]:size-4",
lg: "h-12 px-6 py-3 text-lg [&_svg]:size-5",
icon: "size-10 [&_svg]:size-4",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
loading?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(
{
className,
variant,
size,
asChild = false,
loading = false,
disabled,
children,
...props
},
ref
) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
ref={ref}
className={cn(buttonVariants({ variant, size, className }))}
disabled={disabled || loading}
aria-busy={loading || undefined}
{...props}
>
{loading && <Loader2 className="size-4 animate-spin" aria-hidden="true" />}
<span className={loading ? "opacity-80" : undefined}>{children}</span>
</Comp>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }
import Link from "next/link"
import { Settings } from "lucide-react"
import { Button } from "@/components/ui/button"
export function ExampleActions() {
return (
<div className="flex items-center gap-2">
<Button>저장</Button>
<Button variant="outline">취소</Button>
<Button variant="ghost" size="icon" aria-label="설정 열기">
<Settings aria-hidden="true" />
</Button>
<Button asChild>
<Link href="/dashboard">대시보드로 이동</Link>
</Button>
</div>
)
}
color-error-500, color-error-600, motion-duration-fast, motion-ease-default가 아직 토큰 시스템에 없다면 프로젝트의 기존 semantic token으로 연결하거나 Phase 2 토큰에 추가한다.
| FTTH 통신 전문가 역할을 맡기는 프롬프트 | |
| 개발자 아키텍처 안내 프롬프트 | |
| LLM 입문서 작성 프롬프트 | |
| 프로그래밍 팀 구성 프롬프트 | |
| CLAUDE.md 조립 프롬프트 |