Color
색의 외형이 아니라 의미와 표면 관계로 semantic token을 선택합니다.
목적
Dot의 색은 화면을 꾸미기보다 표면의 관계, 텍스트 위계, 상태, 다음 행동을 구분한다. 기본 경험은 차분한 중립색으로 구성하고, 상태색과 Glow는 의미가 있을 때만 사용한다.
색 판단은 다음 브랜드 행동을 따른다.
- Flexible: 화면·상태·사용자 맥락이 달라도 semantic 의미를 유지한다.
- Link: 같은 상태와 관계에는 화면 전환 뒤에도 같은 색 역할을 사용한다.
- Glow: 불확실한 순간의 다음 방향을 안내할 때만 제한적으로 사용한다.
토큰 사용 계약
색은 primitive → semantic → component 순으로 해석한다. 제품과 React 컴포넌트는 raw 색상값 대신 semantic token을 사용한다.
<div className="bg-surface-raised text-ink-default border-line-subtle" />- 제품 코드에서 hex, rgb, oklch 값을 직접 쓰지 않는다.
- opacity가 필요하면 semantic token에 alpha를 적용하고 새로운 raw 색을 만들지 않는다.
- token의 값이 아니라 역할을 기준으로 선택한다.
- 새 의미가 기존 token에 맞지 않으면 가장 비슷한 색을 재사용하지 말고 semantic token gap을 제안한다.
- token JSON과 CSS variable은 동일한 이름과 값을 유지해야 한다.
Surface
| 토큰 | 역할 | 대표 사용 |
|---|---|---|
surface-canvas | 앱의 가장 낮은 본문 배경 | PageScaffold 주변, 전체 작업 배경 |
surface-raised | 기본 콘텐츠 표면 | section, table, dialog content |
surface-subtle | 낮은 구분과 보조 영역 | filter, hover, metadata group |
surface-emphasis | 선택 또는 중요한 중립 강조 | selected row, active neutral control |
surface-brand-subtle | 제한된 브랜드·AI 안내 배경 | 의미 있는 안내, 드문 AI 맥락 |
표면은 elevation 순서를 만든다. 같은 단계의 section마다 배경을 바꾸지 않는다.
- canvas 위에 raised 표면을 한 단계 사용할 수 있다.
- raised 안의 반복 데이터는 card를 다시 중첩하지 않고 row와
line-subtle로 나눈다. - overlay는
popover또는card계열 component token을 통해 raised 관계를 유지한다. surface-brand-subtle은 일반 정보, 필터, navigation 배경으로 사용하지 않는다.
Ink
| 토큰 | 역할 | 대표 사용 |
|---|---|---|
ink-strong | 가장 중요한 제목·식별 값 | h1, section title, 핵심 metric |
ink-default | 기본 읽기 콘텐츠 | body, field value, table text |
ink-subtle | 보충 정보 | description, timestamp, metadata |
ink-disabled | 사용할 수 없는 텍스트 | disabled label, unavailable value |
ink-subtle에 행동 전 필수 조건이나 오류 원인을 숨기지 않는다.- disabled는 opacity만 낮추지 않고 상호작용도 실제로 비활성화한다.
- placeholder는 입력값보다 낮은 계층이지만 정보 전달의 유일한 수단이 아니다.
- 링크는 색만으로 본문과 구분하지 않고 문맥에 따라 underline, 위치, 명확한 레이블을 사용한다.
Line
| 토큰 | 역할 | 대표 사용 |
|---|---|---|
line-subtle | 기본 분리와 구조 | table row, section boundary, card border |
line-strong | 선택·강조·입력 경계 | active boundary, stronger control state |
input | 입력 control의 기본 경계 | Input, Select |
ring | keyboard focus 표시 | focus-visible ring |
- border는 실제 그룹이나 control 경계를 표현할 때만 쓴다.
- 모든 section에 border를 추가하지 않는다. 여백과 제목으로 충분한지 먼저 확인한다.
- focus ring은 hover나 selected 색과 구분되어야 한다.
- validation error가 생겨도 focus ring을 제거하지 않는다. error와 focus를 함께 식별할 수 있어야 한다.
Action color
| 토큰 | 의미 | 사용 |
|---|---|---|
primary / primary-foreground | 화면의 주 행동 | Button default |
secondary / secondary-foreground | 보조 행동 | Button secondary |
accent / accent-foreground | hover·선택의 낮은 강조 | ghost hover, menu selection |
muted / muted-foreground | 비활성에 가까운 보조 표면 | 설명 영역, skeleton과 보조 UI |
destructive / destructive-foreground | 파괴 행동과 실패 | 삭제 trigger, destructive result |
한 화면에서 primary action은 하나다. 색을 강하게 쓴다고 행동의 우선순위가 해결되지는 않는다. 위치, 레이블, 그룹을 먼저 정한다.
Status color
| 토큰 | 의미 | 예 |
|---|---|---|
success | 의도한 작업이 확인된 범위에서 완료 | 저장됨, 검증 통과 |
warning | 계속할 수 있지만 확인 또는 조치가 필요 | 만료 임박, 일부 누락 |
destructive | 실패, 위험, 되돌릴 수 없는 결과 | 발송 실패, 삭제 |
info | 중립적인 진행·환경·참고 상태 | 처리 예정, 동기화 정보 |
- 상태에는 텍스트 레이블을 반드시 함께 제공한다.
- 같은 상태 이름은
StatusPill의 같은 tone을 사용한다. - warning과 destructive를 단순한 중요도 차이로 선택하지 않는다. 사용자가 계속 진행할 수 있는지와 피해 가능성으로 판단한다.
primary를 상태색으로 사용하지 않는다.success는 요청을 받았다는 뜻이 아니라 결과가 확인됐을 때 사용한다.
Sidebar와 overlay
Sidebar에는 sidebar, sidebar-foreground, sidebar-border, sidebar-accent, sidebar-primary, sidebar-ring component token을 사용한다. 일반 surface token으로 임의 재구성해 selected·focus 관계를 바꾸지 않는다.
Dialog, Popover, Sheet, Tooltip은 DotTheme 내부 portal root에서 theme token을 상속한다. overlay에 raw white·black을 지정해 theme 경계를 우회하지 않는다.
Brand와 Glow
브랜드 색의 순서는 brand-dot-pink → brand-dot-magenta → brand-dot-violet → brand-dot-blue다. 구현은 승인된 .bg-dot-gradient, .text-dot-gradient utility만 사용한다.
적합한 사용:
- 드문 온보딩·완료의 핵심 시그니처
- AI가 실제로 안내하거나 처리하는 맥락의 제한된 강조
- 다음 방향이 불분명한 순간의 작은 안내 영역
피해야 할 사용:
- 기본 Primary 버튼
- 앱 전체 배경과 Sidebar
- table row, 일반 Card, 모든 AI section
- 오류·경고·삭제 상태
- 긴 본문과 핵심 수치의 gradient text
Glow는 한 화면에서 여러 요소가 경쟁하지 않게 한다. 캐릭터와 함께 사용할 때 지정된 색, 요소 관계, 여백을 바꾸지 않는다.
Chart color
chart-1부터 chart-5는 데이터 계열 구분에 사용할 수 있다.
- 한 화면 안에서 같은 계열은 같은 색을 유지한다.
- 색 순서만으로 좋음·나쁨을 암시하지 않는다.
- legend, label, pattern, 직접 표시 중 하나로 색 외의 구분을 제공한다.
- 5개를 넘는 계열은 색을 더 만들기보다 grouping, filter, small multiples를 검토한다.
- 정확한 값과 상태가 중요하면 표와 텍스트를 함께 제공한다.
- brand gradient를 연속형 데이터 scale로 사용하지 않는다.
상태와 접근성
- body와 정보 텍스트의 대비는 실제 배경 조합에서 검증한다.
- focus, hover, selected, disabled를 색 하나의 변화만으로 구분하지 않는다.
- status는 icon·label·문장 중 필요한 신호를 함께 제공한다.
- forced colors, high contrast, zoom 환경에서도 control 경계와 focus가 보이는지 확인한다.
- gradient text를 사용할 때 색 효과가 제거돼도 읽을 수 있는 fallback을 제공한다.
- loading skeleton은 최종 콘텐츠와 혼동되지 않는 낮은 대비를 사용하되 사라진 콘텐츠처럼 보이지 않게 한다.
- motion 감소 설정은 색 의미를 바꾸지 않는다.
예외와 피해야 할 사용
- raw color와 임의의 투명도로 새로운 상태를 만들지 않는다.
- 회색이 차분하다는 이유로 모든 텍스트를
ink-subtle로 만들지 않는다. - 한 상태에 화면마다 다른 tone을 쓰지 않는다.
- disabled, read-only, unavailable을 같은 표현으로 합치지 않는다.
- 배경색으로만 clickable 영역을 표시하지 않는다.
- shadow와 어두운 border를 동시에 사용해 elevation을 과장하지 않는다.
- 캐릭터의 색을 주변 UI에 맞춰 변경하지 않는다.
- Glow를 신뢰, 정확성, 완료를 보장하는 신호처럼 사용하지 않는다.
검토 질문
- 모든 색이 raw 값이 아닌 semantic 역할로 선택됐는가?
- surface 단계가 실제 구조와 일치하고 card가 중첩되지 않는가?
ink-subtle에 중요한 조건을 숨기지 않았는가?- 상태가 색 없이도 이해되는가?
- 같은 상태가 화면 전환 뒤에도 같은 token과 용어를 사용하는가?
- focus와 selected, error 상태를 동시에 구분할 수 있는가?
- chart를 색 없이도 읽고 비교할 수 있는가?
- Glow가 다음 방향을 안내하는 드문 순간에만 쓰였는가?
- 브랜드 색과 캐릭터의 지정 관계를 변경하지 않았는가?
- theme 밖의 raw 색이나 overlay 예외가 생기지 않았는가?