Design TokensP2 본문

디자인 토큰

Primitive → Semantic → Component 3계층 토큰의 구조와 규칙, Web/Flutter 소비 방법. 한 곳(JSON SSOT)을 고치면 두 플랫폼이 함께 바뀝니다.

마지막 업데이트 2026-06-12

3계층 구조#

토큰 정본은 tokens/ 디렉토리의 W3C Design Tokens JSON 하나입니다(AD-2). codegen(make tokens)이 CSS 변수와 Dart 상수를 동시에 생성합니다.

Primitive(core) — 원시 값. 램프와 스케일 → Semantic — 의도. 라이트/다크 2세트 → Component — 컴포넌트별 결정

계층참조 규칙위반 시
coreliteral만 (alias 금지)빌드 실패
semanticcore만 참조빌드 실패
componentsemantic만 참조 (primitive 직접 참조 금지 — AD-2 #4)빌드 실패

토널 램프 (Primitive 생성)#

core 램프는 손으로 고른 hex가 아니라 톤 수학으로 생성됩니다(ADR-013). 톤 번호는 곧 CIELAB L*(지각 명도, D65) — t40은 모든 hue에서 같은 명도라, 두 색의 대비가 톤 차이만으로 결정됩니다. Material 3의 tonal palette와 같은 정의를 HCT 엔진 없이 scripts/build-tokens/src/tonal.ts(culori lch65)로 구현했습니다.

neutral — 24톤 (표면·상태 레이어 기반)
0
4
6
10
12
17
20
22
24
30
40
50
60
70
80
87
90
92
94
95
96
98
99
100
  • t22다크 surface-raised (tone 수학 파생)
  • t40M3 라이트 전경 기준
  • t80M3 다크 전경 기준

톤 번호 = CIELAB L*(지각 명도, D65) — 0 검정 → 100 흰색. 같은 번호는 모든 hue에서 같은 명도라 대비가 톤 차이로 결정됩니다.

색 램프는 표준 13톤입니다 — t40(라이트 기준)과 t80(다크 기준)의 대칭이 테마 전환 공식이 됩니다.

blue
0
10
20
30
40
50
60
70
80
90
95
99
100
  • t40라이트 primary
  • t80다크 primary

톤 번호 = CIELAB L*(지각 명도, D65) — 0 검정 → 100 흰색. 같은 번호는 모든 hue에서 같은 명도라 대비가 톤 차이로 결정됩니다.

green
0
10
20
30
40
50
60
70
80
90
95
99
100

톤 번호 = CIELAB L*(지각 명도, D65) — 0 검정 → 100 흰색. 같은 번호는 모든 hue에서 같은 명도라 대비가 톤 차이로 결정됩니다.

red
0
10
20
30
40
50
60
70
80
90
95
99
100

톤 번호 = CIELAB L*(지각 명도, D65) — 0 검정 → 100 흰색. 같은 번호는 모든 hue에서 같은 명도라 대비가 톤 차이로 결정됩니다.

amber
0
10
20
30
40
50
60
70
80
90
95
99
100

톤 번호 = CIELAB L*(지각 명도, D65) — 0 검정 → 100 흰색. 같은 번호는 모든 hue에서 같은 명도라 대비가 톤 차이로 결정됩니다.

sky
0
10
20
30
40
50
60
70
80
90
95
99
100

톤 번호 = CIELAB L*(지각 명도, D65) — 0 검정 → 100 흰색. 같은 번호는 모든 hue에서 같은 명도라 대비가 톤 차이로 결정됩니다.

램프는 승인된 기존 팔레트의 실측 (L*, C, H) 프로파일을 보간해 생성합니다 — 체계화이지 리베이스가 아닙니다. 빌드 게이트가 앵커 충실도(기존 색을 채널 Δ≤2로 재현)와 톤 대비 법칙(Δtone≥504.4:1, 명시 전경/배경 페어 → 4.5:1)을 매 빌드 검증합니다. 새 브랜드 컬러는 프로파일 한 줄이면 전체 톤·상태 레이어가 자동 파생됩니다.

네이밍#

JSON 경로가 그대로 CSS 변수명과 Dart 상수명이 됩니다.

JSON 경로CSSDart
blue.600--wds-blue-600WizPalette.blue600
color.primary--wds-color-primaryWizColors.light.primary / .dark.primary
font.size.body-1--wds-font-size-body-1WizTypography.sizeBody1
space.4--wds-space-4WizSpacing.s4
button.bg--wds-button-bgWizButtonTokens.light.bg

사용법#

Web — CSS 변수#

alias는 var() 참조로 유지됩니다(테마 전환은 [data-theme]가 처리).

.card {
  background: var(--wds-color-surface);
  border-radius: var(--wds-radius-md);
  padding: var(--wds-space-6);
  box-shadow: var(--wds-shadow-sm);
}

Flutter — 생성 상수#

Dart 타겟은 빌드타임에 평면화됩니다 — rem은 px(×16) double로, shadow는 BoxShadow로, duration은 Duration으로, 이징은 Cubic으로 변환됩니다.

import 'package:wiz_ui/wiz_ui.dart';

Container(
  color: WizColors.light.surface,          // 다크: WizColors.dark.surface
  padding: const EdgeInsets.all(WizSpacing.s6),
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(WizRadius.md),
    boxShadow: const [WizShadows.sm],
  ),
)

두 타겟의 일치는 교차 타겟 테스트가 보증합니다 — 모든 시멘틱 컬러의 light/dark computed 값이 CSS와 Dart에서 동일함을 매 빌드 검증.

시멘틱 컬러 전체#

라이트가 정본, 다크는 오버라이드입니다. 상세 설계 근거는 다크 모드 참조.

토큰라이트다크설명
AA 안전 채움 — 일반 크기(16px) 텍스트 버튼용 (DD-6 정책, P3 신설)
소형 텍스트용 Primary — bg·surface·surface-selected·primary-subtle 표면에서 AA 보장(매트릭스 고정). surface-muted 위 사용 금지
nav 활성/선택 표면(블루 틴트)
떠 있는 표면(그림자로 위계)
P2 의도 변경(시드 gray.400→500) — 400은 백색 입력면에서 2.54:1, placeholder도 텍스트(AA 대상). parity 예외 기록
옅은 구분선/보더
P2 의도 변경(시드 blue.600→700) — 600은 모든 라이트 표면에서 4.39:1로 AA 미달. parity 예외 목록 기록
P2 의도 변경(시드 blue.700→800) — link 승격에 따른 hover 단계 이동
상태 표시(아이콘/보더/배지) — 텍스트는 success-text 사용
상태 표시 전용 — 라이트 표면 텍스트/단독 아이콘 금지(대비 2.2:1), warning-text + 아이콘 병용
상태 표시 — 텍스트는 error-text 사용
상태 표시 — 텍스트는 info-text 사용
상태 텍스트 — AA 4.5:1 (P2 신설)
상태 텍스트 — AA 4.5:1 (P2 신설)
상태 텍스트 — AA 4.5:1 (P2 신설)
상태 텍스트 — AA 4.5:1 (P2 신설)
비활성 컨트롤 배경 (P1 신설)
비활성 컨트롤 전경 (P1 신설)
모달/드로어 스크림 (P1 신설)
본문 검색어 하이라이트 배경 — ::highlight(wds-search) (P1 신설)
A1 신설 — 보조 키 컬러(브랜드 시안 인접). M3 base tone40(라이트)
A1 신설 — secondary 채움 위 잉크. M3 on-base tone100
A1 신설 — 보조 컨테이너 표면. M3 container tone90
A1 신설 — secondary-container 위 잉크. M3 on-container tone10
A1 신설 — 3차 키 컬러(primary +60° 회전). M3 base tone40(라이트)
A1 신설 — tertiary 채움 위 잉크. M3 on-base tone100
A1 신설 — 3차 컨테이너 표면. M3 container tone90
A1 신설 — tertiary-container 위 잉크. M3 on-container tone10
A1 신설 — primary 컨테이너 표면(기존 primary-subtle와 별개의 on- 페어 보유 컨테이너). M3 container 대응
A1 신설 — primary-container 위 잉크. M3 on-container 대응
A1 신설 — surface-container 5티어 최저(가장 밝음). M3 light tone100. 이 5티어가 surface 톤 SSOT(00 §3.2) — Track B 머티리얼 매핑은 5-4 결정
A1 신설 — surface-container 티어 low. M3 light tone96
A1 신설 — surface-container 티어 기본. M3 light tone94
A1 신설 — surface-container 티어 high. M3 light tone92
A1 신설 — surface-container 티어 최고. M3 light tone90
A1 신설 — M3 outline(경계/구분 UI). surface 위 UI 3:1. M3 light tone50
A1 신설 — M3 outline-variant(장식 디바이더). 비게이트(저대비 의도, border-subtle와 동급). M3 light tone80
A1 신설 — 반전 표면(스낵바/토스트). M3 light tone20
A1 신설 — inverse-surface 위 잉크. M3 light tone95
A1 신설 — inverse-surface 위 primary 액센트(다크 primary tone). M3 light=tone80
A1 신설 — 에러 컨테이너 표면(기존 error 표시색과 별개의 컨테이너 페어). M3 container tone90
A1 신설 — error-container 위 잉크. M3 on-container tone10
서포팅 액센트 사용 토큰 — 태그/카테고리 칩 배경(violet). text와 AA 4.5:1(contrast.test 게이트). UI 본문 색 아님(절제)
tag-violet-bg 위 라벨/아이콘 잉크 — AA 4.5:1
솔리드 채움(아바타/도트/카테고리 점) — 그래픽 요소. 본문 텍스트 배경 아님(대형 텍스트만)
서포팅 액센트 사용 토큰 — 태그/카테고리 칩 배경(teal). text와 AA 4.5:1
tag-teal-bg 위 라벨/아이콘 잉크 — AA 4.5:1
솔리드 채움(아바타/도트) — 그래픽 요소
서포팅 액센트 사용 토큰 — 태그/카테고리 칩 배경(magenta). text와 AA 4.5:1
tag-magenta-bg 위 라벨/아이콘 잉크 — AA 4.5:1
솔리드 채움(아바타/도트) — 그래픽 요소
서포팅 액센트 사용 토큰 — 태그/카테고리 칩 배경(orange). Warning(amber)과 용도 구분: 장식·카테고리. text와 AA 4.5:1
tag-orange-bg 위 라벨/아이콘 잉크 — AA 4.5:1
솔리드 채움(아바타/도트) — 그래픽 요소
서포팅 액센트 사용 토큰 — 태그/카테고리 칩 배경(cyan). text와 AA 4.5:1
tag-cyan-bg 위 라벨/아이콘 잉크 — AA 4.5:1
솔리드 채움(아바타/도트) — 그래픽 요소
상태 컨테이너 — 연한 Success 표면(부드러운 알림/배지 바탕). M3 container tone90
success-container 위 잉크. M3 on-container tone10 (AA)
상태 컨테이너 — 연한 Warning 표면. M3 container tone90
warning-container 위 잉크. M3 on-container tone10 (AA)
상태 컨테이너 — 연한 Info 표면. M3 container tone90
info-container 위 잉크. M3 on-container tone10 (AA)
수식 생성(state-layer.ts) — text 8% over surface (M3 state layer, ADR-013 T3)
수식 생성(state-layer.ts) — text 12% over surface (M3 state layer, ADR-013 T3)

컴포넌트 토큰#

semantic만 참조합니다 — 테마는 참조 경로를 따라 자동 적용됩니다.

토큰설명
DD-6 해소: 버튼 라벨은 항상 일반 크기(≤16px) → 기본 채움이 AA 4.5:1을 보장해야 한다 (라이트 Blue700, 7.3:1)
P3 신설 — invalid 상태 보더

변경 절차#

토큰 변경은 영향 등급(Token Impact Matrix)에 따라 차등 승인됩니다 — Primitive 변경은 Governance Board 승인(High), 문서 수정은 Owner 승인(Low). 전체 절차는 MASTER_PLAN §12 참조.

P2 확정 기록#

항목결정근거
Blue 700 표기 모호#1252B2 확정시각 대조 — #125282(라벨)는 램프 hue 연속성 파괴
Warning 표기 모호#F59E0B 확정두 후보 시각 구분 불가 — 업계 표준값 채택
color.linkblue.600 → 700 승격 (의도 변경)600은 모든 라이트 표면에서 4.39:1 — AA 미달
color.on-primary(다크)white → gray.900 반전다크 primary(blue.500) 위 백색은 2.96:1
color.text-placeholder라이트 gray.400→500 / 다크 500→400 (의도 변경)placeholder도 텍스트 — 시드값은 백색 입력면 2.54:1
Button 600+백색 (DD-6)large text 전용 정책4.39:1 ≥ 3:1(large) — 일반 텍스트 버튼은 P3에서 strong 변형