아이코노그래피
24px 그리드 · 1.8px 스트로크 아웃라인 아이콘 체계와 SVG → React 생성 파이프라인. 아이콘 추가는 SVG 1개 + make icons 로 끝납니다.
마지막 업데이트 2026-06-24
원칙#
WDS 아이콘은 24×24 그리드의 스트로크(아웃라인) 세트 하나로 시작합니다(ADR-011).
- 그리드
- 24×24 viewBox
icon.size-lg - 스트로크
- 1.8px
icon.stroke - 캡 · 조인
- round
- 색
- currentColor 상속
ADR-011 §2
| 원칙 | 값 | 근거 |
|---|---|---|
| 그리드 | 24×24 viewBox 고정 | icon.size-lg(24px)와 동일 기준, 축소 렌더에도 정수 정렬 |
| 스트로크 | 1.8px (icon.stroke) | 20px 기본 렌더에서 1.5px(가늘다)와 2px(둔하다)의 중간 — Blue 잉크와 균형 |
| 캡/조인 | round | 브랜드 심볼의 둥근 기하와 동일 어휘 |
| 색 | currentColor 상속 | 아이콘 전용 색 토큰은 색 결정을 이원화하므로 금지 (ADR-011 §2) |
| Filled 세트 | 후속 | 탭바/토글 등 “선택됨” 표현이 필요해지는 시점에 추가 |
색이 없다는 것이 핵심 규칙입니다. 아이콘은 항상 부모 텍스트 색을 그대로 상속하므로,
색을 바꾸고 싶다면 부모(또는 아이콘 자신)의 color에 semantic 토큰을 지정합니다.
크기 토큰#
크기·스트로크는 semantic 계층입니다 — 여러 컴포넌트가 공유하는 “의도”이지 특정 컴포넌트의 결정이 아니기 때문입니다(ADR-011 §1).
| 토큰 | 값 | 설명 |
|---|---|---|
| 토큰 | 렌더 | 쓰임 |
|---|---|---|
icon.size-sm (16px) | 인라인 | 본문 텍스트 옆 · 캡션 · 칩 내부 |
icon.size-md (20px) | 컨트롤 기본 | 버튼·인풋·메뉴 항목 — 생성 컴포넌트의 기본값 |
icon.size-lg (24px) | 단독/강조 | 헤더 액션 · 빈 상태 · 아이콘 그리드 원본 크기 |
코어 아이콘셋#
웹·모바일 앱 제작에 필요한 표준 베이스라인을 카테고리별로 갖춥니다 — 내비게이션·액션·사용자·커뮤니케이션·미디어·파일·커머스·기기·상태까지.
아래 갤러리는 생성된 React 컴포넌트(ICON_REGISTRY)를 카테고리별로 그룹화해 렌더하며,
상단 검색창으로 이름(예: arrow, cloud)을 좁혀볼 수 있습니다 — 레지스트리를 직접 소비하므로 항상 구현과 일치합니다.
각 아이콘의 카테고리는 코드젠 소스(scripts/build-icons/src/categories.ts)가 정본이며, 모든 아이콘은 정확히 하나의 카테고리에 속합니다(미분류 시 make icons 실패).
내비게이션
17- ArrowBackUpIcon
- ArrowDownIcon
- ArrowForwardUpIcon
- ArrowLeftIcon
- ArrowRightIcon
- ArrowsSortIcon
- ArrowUpIcon
- ArrowUpRightIcon
- ChevronDownIcon
- ChevronLeftIcon
- ChevronRightIcon
- ChevronUpIcon
- CompassIcon
- ExternalLinkIcon
- HomeIcon
- LinkIcon
- MenuIcon
액션
27- AdjustmentsIcon
- ArchiveIcon
- BanIcon
- BoltIcon
- CheckIcon
- CloseIcon
- CopyIcon
- DotsIcon
- DotsVerticalIcon
- DownloadIcon
- EditIcon
- FilterIcon
- MaximizeIcon
- MinimizeIcon
- MinusIcon
- PencilIcon
- PinIcon
- PlusIcon
- RefreshIcon
- ScanIcon
- SearchIcon
- SettingsIcon
- ToolIcon
- TrashIcon
- UploadIcon
- ZoomInIcon
- ZoomOutIcon
사용자
13- FingerprintIcon
- IdIcon
- KeyIcon
- LockIcon
- LockOpenIcon
- LoginIcon
- LogoutIcon
- ShieldCheckIcon
- ShieldIcon
- ShieldLockIcon
- UserCircleIcon
- UserIcon
- UsersIcon
커뮤니케이션
6- AtIcon
- BellIcon
- MailIcon
- MessageIcon
- PhoneIcon
- SendIcon
상태
16- AlertTriangleIcon
- BookmarkIcon
- CheckCircleIcon
- CircleAlertIcon
- CircleMinusIcon
- CirclePlusIcon
- CircleXIcon
- FlagIcon
- HeartIcon
- HelpIcon
- HourglassIcon
- InfoIcon
- LoaderIcon
- StarIcon
- ThumbDownIcon
- ThumbUpIcon
레이아웃
8- CategoryIcon
- DashboardIcon
- LayoutColumnsIcon
- LayoutGridIcon
- LayoutSidebarIcon
- LayoutSidebarListIcon
- LayoutSidebarRightIcon
- ListIcon
파일
12- BookOpenIcon
- ClipboardIcon
- FileIcon
- FilePlusIcon
- FilesIcon
- FileSpreadsheetIcon
- FileTextIcon
- FileZipIcon
- FolderIcon
- FolderOpenIcon
- PrinterIcon
- QrcodeIcon
미디어
13- AudioLinesIcon
- CameraIcon
- ImageIcon
- MicrophoneIcon
- MusicIcon
- PlayerPauseIcon
- PlayerPlayIcon
- PlayerSkipBackIcon
- PlayerSkipForwardIcon
- StopIcon
- VideoIcon
- VolumeIcon
- VolumeOffIcon
커머스
8- CoinIcon
- CreditCardIcon
- GiftIcon
- ReceiptIcon
- ShoppingBagIcon
- ShoppingCartIcon
- TagIcon
- WalletIcon
기기
7- BatteryIcon
- BluetoothIcon
- DeviceDesktopIcon
- DeviceLaptopIcon
- DeviceMobileIcon
- WifiIcon
- WifiOffIcon
시간
5- AlarmIcon
- CalendarEventIcon
- CalendarIcon
- ClockIcon
- HistoryIcon
위치
4- GlobeIcon
- LocationIcon
- MapIcon
- MapPinIcon
소셜
2- BulbIcon
- MoodSmileIcon
텍스트
5- AlignCenterIcon
- AlignLeftIcon
- BoldIcon
- ItalicIcon
- UnderlineIcon
날씨
8- CloudDownloadIcon
- CloudIcon
- CloudRainIcon
- CloudUploadIcon
- MoonIcon
- SnowflakeIcon
- SunIcon
- TemperatureIcon
기타
4- CodeIcon
- EyeIcon
- EyeOffIcon
- PaperclipIcon
| 컴포넌트 | 소스 | 주 용도 |
|---|---|---|
SearchIcon | search.svg | 검색(⌘K / Ctrl K) |
CloseIcon | close.svg | 다이얼로그·칩 닫기 |
MenuIcon | menu.svg | 모바일 내비게이션 |
SunIcon / MoonIcon | sun.svg / moon.svg | 테마 토글 |
CopyIcon / CheckIcon | copy.svg / check.svg | 복사 인터랙션(복사 → 완료) |
LinkIcon | link.svg | 헤딩 앵커 |
ChevronDownIcon / ChevronRightIcon | chevron-*.svg | 아코디언·트리·브레드크럼 |
ArrowUpIcon | arrow-up.svg | AI 입력 전송 |
ExternalLinkIcon | external-link.svg | 외부 링크 표시 |
InfoIcon | info.svg | 안내 배너 |
CircleAlertIcon | circle-alert.svg | 에러 상태(경고 삼각형과 변별) |
FileTextIcon / GlobeIcon / BookOpenIcon | file-text.svg / globe.svg / book-open.svg | 지식 소스(문서·웹·위키) |
ImageIcon | image.svg | 이미지·썸네일 플레이스홀더 |
StopIcon | stop.svg | AI 응답 중단 |
렌더링 모드 (mono · hierarchical)#
생성 컴포넌트는 renderingMode prop으로 두 모드를 가집니다(Track B 5-1 Phase 1).
기본값은 mono — 현행 단색 아웃라인과 바이트 동일합니다. 즉 renderingMode를
지정하지 않은 모든 기존 사용처는 한 픽셀도 바뀌지 않습니다.
| 모드 | 색 | 깊이 | 쓰임 |
|---|---|---|---|
mono (기본) | currentColor 단색 | 없음(평면) | 본문·컨트롤·인라인 — 거의 전부 |
hierarchical | currentColor (농도만 분리) | Bloom Depth 2단 | 빈상태·강조·단독 노출에서 위계가 필요할 때 |
hierarchical는 Bloom Depth 농도 표현입니다(§0 시각 POV). 보조/컨테이너 레이어가
ICON_HIERARCHICAL_SECONDARY(0.4) 농도로 물러나고, 주체는 농도 1로 남아 한 색 안에서
깊이가 생깁니다 — WDS 아이콘의 계층형 표현 어휘입니다. 두 모드 모두 currentColor를
상속하므로 색 정책(ADR-011 §2)은 그대로입니다. 명시 색(palette)·2색(duotone)은 범위 밖(후속).
레이어 주석(data-layer="2")이 없는 글리프는 두 모드에서 동일하게 렌더됩니다 — opacity가
주입되지 않습니다. 현재 4종(check-circle · info · calendar · alert-triangle)이 PoC로 보조
레이어를 가집니다 — 모두 보조 레이어가 **컨테이너/배경 프레임(원·사각·삼각)**이고 주체(체크·정보 점·
날짜 그리드·경고 ”!”)는 농도 1로 남는 글리프입니다. 아래는 mono(좌) ↔ hierarchical(우) 비교입니다.
- CheckCircleIcon
- InfoIcon
- CalendarIcon
- AlertTriangleIcon
- CircleAlertIcon
- FileTextIcon
- GlobeIcon
- ImageIcon
접근성 주의 — hierarchical은 장식·대형 전용. 보조 tier는
ICON_HIERARCHICAL_SECONDARY(0.4) 농도로 합성되며, currentColor가 충분히 진하지 않으면 WCAG 1.4.11(비텍스트 대비 3:1)을 보장하지 못합니다. 특히icon.size-sm(16px)에서는 0.4 농도의 가는 스트로크가 지각되지 않으므로, hierarchical은 20–24px 이상의 단독·강조·빈상태 표면에서만 쓰고 16px 인라인에는 쓰지 않습니다. 핵심 규칙: 물러나는 레이어는 반드시 컨테이너/배경 프레임(원·사각·삼각)이어야 하며, 글리프의 정체성을 이루는 주체(alert-triangle의 ”!” 등)는 농도 1로 남아야 합니다 — 농도가 의미의 유일한 전달자가 되어선 안 됩니다. 프레임과 주체가 명확히 분리되지 않는 글리프(예: 대칭link)는 PoC에서 제외했습니다.
import { AlertTriangleIcon } from '@wds/ui-web';
// 기본 mono — 현행과 동일
<AlertTriangleIcon />
// hierarchical — 삼각 프레임이 농도로 물러나고 "!" 주체는 농도 1로 남음
<AlertTriangleIcon renderingMode="hierarchical" />
소스에서 보조 요소에
data-layer="2"한 줄만 부여하면 생성기가 모드 분기를 만듭니다. 이 주석은 소스 전용 — 생성 출력에선 제거되고 hierarchical에서만opacity로 변환됩니다.
옵티컬 스트로크 (설계 노트)#
작은 렌더에서 stroke가 시각적으로 가늘어지는 것을 막으려면 작은 size일수록 viewBox
stroke를 키워야 합니다(옵티컬 보정). Phase 1은 이 테이블을 설계·노출만 합니다 —
기본 컴포넌트는 여전히 ICON_STROKE(1.8px)를 그대로 쓰므로 비기본 size의 픽셀이 바뀌지
않습니다(무손상). 기본 적용은 Phase 2 결정입니다.
16px 확대 — 렌더 스트로크 1.2px(보정 전) vs 1.5px(보정 후)
공식 (24 그리드가 앵커):
strokeForSize(size) = ICON_STROKE × (1 − d + d × 24 / size), d = 0.5
| 렌더 size | viewBox stroke | 비고 |
|---|---|---|
16px (icon.size-sm) | 2.25px | 가장 강한 보정 |
20px (icon.size-md) | 1.98px | 컨트롤 기본 |
24px (icon.size-lg) | 1.8px | 앵커 — ICON_STROKE 그대로 |
d = 0.5는 절반 보정입니다 — 완전 역스케일(d = 1, 렌더 px 완전 균일)은 작은 글리프를
과하게 두껍게 만들기 때문입니다. ICON_OPTICAL_STROKE 테이블과 strokeForSize(size)
헬퍼를 @wds/ui-web에서 노출합니다(소비처가 직접 적용 가능).
파이프라인 — SVG 1개 = 아이콘 1개#
아이콘 React 코드는 수기 작성 금지 — 전부 생성물입니다.
# 1. 24×24 스트로크 SVG를 icons/ 에 추가
# 2. 생성 실행
make icons
# → packages/ui-web/src/icons/<Name>Icon.tsx + index.ts 전체 재생성
생성기는 tokens/dist/manifest.json에서 icon.size-md·icon.stroke를 읽어
상수로 박습니다 — 토큰을 바꾸면 다음 make icons에서 아이콘도 함께 바뀝니다(SSOT).
소스 규격 (빌드가 강제)#
- 루트:
viewBox="0 0 24 24"·fill="none"·stroke="currentColor"— width/height 금지 - 내부:
path·circle·rect등 기하 요소만,fill·kebab 속성(stroke-width등) 금지 - 파일명:
kebab-case.svg→PascalCase + Icon(예:external-link.svg→ExternalLinkIcon)
규격 위반은 make icons가 한국어 메시지와 함께 실패시킵니다.
사용법#
import { SearchIcon, CopyIcon } from '@wds/ui-web';
// 기본 20px(icon.size-md) · 부모 색 상속
<SearchIcon />
// 크기 지정 — 토큰 3단(16/20/24) 안에서
<CopyIcon size={16} />
// 색은 부모가 결정한다
<span style={{ color: 'var(--wds-color-primary)' }}>
<SearchIcon />
</span>
접근성#
- 생성 컴포넌트는 기본
aria-hidden="true"— 아이콘은 장식이 기본값입니다. - 아이콘이 의미를 단독 전달하면(아이콘 전용 버튼 등) 컨테이너에 라벨을 부여합니다:
<button type="button" aria-label="검색">
<SearchIcon />
</button>
- 아이콘+텍스트 병기 시에는 텍스트가 이름이 되므로 추가 라벨이 필요 없습니다.
후속 (P5)#
- Dart 타겟 — 렌더 방식(아이콘 폰트/flutter_svg/CustomPaint) 결정과 함께 P5 WizTheme에서. 그 전까지 Flutter는 Material 아이콘 임시 사용 (ADR-011 §5)
- Filled 세트 — Outlined와 1:1 쌍으로 추가, “선택됨” 상태 표현용
- 앱 아이콘 — 마스터/플랫폼 파생 규칙은 04 브랜드 아이덴티티 확장으로