상태 하나가 계산되는 방식
각 상태는 RGBA 픽셀에 적용하는 순서 있는 연산 목록입니다. 외곽선이 있으면 먼저 캔버스를 키우고, 밝기는 값 × 255를 R·G·B에 더하며, 대비는 중간 회색(128)을 기준으로 늘이고, 채도는 각 채널을 그 픽셀의 휘도(0.2126 R + 0.7152 G + 0.0722 B)에서 멀어지거나 가까워지게 합니다. 이어서 선택형 색 덧씌우기, 픽셀 이동, 모양을 네모로 팽창시킨 외곽선을 그리고, 마지막에 알파를 곱합니다. 완전히 투명한 픽셀은 다시 칠하지 않습니다.
엔진은 이 이미지들을 정해진 칸에 받습니다. Godot 4의 TextureButton에는 texture_normal, texture_hover, texture_pressed, texture_disabled, texture_focused가 있고, 자기 텍스처가 없는 disabled 버튼은 normal을 보여 주며, focused 텍스처는 기본 텍스처 위에 겹쳐 그려집니다. Unity UI Button은 Transition을 Sprite Swap으로 두면 Target Graphic의 기본 스프라이트와 Highlighted·Pressed·Disabled 스프라이트를 받습니다.
게임은 웹 페이지가 아니지만 WCAG 2.2의 두 규칙은 알아 둘 만합니다. 성공 기준 1.4.3은 비활성(disabled) 컴포넌트의 텍스트를 대비 최소 기준에서 제외하므로, 흐린 disabled 상태가 허용됩니다. 2.4.13 Focus Appearance(AAA)는 컴포넌트 둘레 2 CSS px 이상 크기의 포커스 표시와, 포커스 전후 픽셀 사이 3:1 대비를 요구합니다. 기본 링은 2px이고 #3182f6은 흰색 대비 3.71:1로 측정됩니다.
- 밝기
- 모든 채널에 더하는 값. +0.1은 +25.5단계입니다.
- 채도
- +0.08은 각 채널을 휘도에서 8% 더 멀리, −1은 픽셀을 회색으로 만듭니다.
- 오프셋
- 같은 캔버스 안에서 픽셀을 옮깁니다. 밖으로 나간 것은 버리고 들어오는 곳은 투명합니다.
- 외곽선
- 불투명한 모양 둘레의 지정 색·두께 링. 캔버스가 그 두께만큼 커집니다.
예시: 픽셀 하나가 기본 상태 다섯 개를 거치면
색 (200, 120, 40)으로 채운 40 × 16 버튼입니다. 내보낸 PNG에 실제로 들어가는 값입니다.
상태 픽셀 (R, G, B, A) 크기 연산
normal (200, 120, 40, 255) 40 × 16 없음
hover (231, 145, 58, 255) 40 × 16 밝기 +0.1 (+25.5), 채도 +0.08
pressed (174, 94, 14, 255) 40 × 16 밝기 −0.1, 오프셋 0,1 → 0번 줄이 투명해짐
disabled (131, 131, 131, 128) 40 × 16 채도 −1, 알파 × 0.5
focus (200, 120, 40, 255) 44 × 20 캔버스 변마다 +2px, 2px 링 (49, 130, 246)
disabled 회색 0.2126 × 200 + 0.7152 × 120 + 0.0722 × 40 = 131.2 → 131; 알파 255 × 0.5 = 127.5 → 128
hover 초록 휘도 156.7 + (145.5 − 156.7) × 1.08 = 144.6 → 145
focus 이미지는 다른 상태보다 가로·세로 4px 크고, 외곽선이 네모 팽창이라 모서리 픽셀까지 링이 덮습니다. states.json에 상태마다 크기와 여백이 기록되므로 차이에 놀랄 일은 없습니다.
Godot·Unity에서 상태 쓰기
- Godot 4:
TextureButton을 추가하고 normal.png·hover.png·pressed.png·disabled.png를 texture_normal·texture_hover·texture_pressed·texture_disabled에 지정합니다. - Godot 4는
texture_focused를 기본 텍스처 위에 그리며, 문서는 외곽선처럼 일부가 투명한 이미지를 권합니다. focus.png에는 버튼 전체가 들어 있으므로 이 칸에 쓰려면 이미지 편집기에서 링 안쪽의 버튼을 지우고 44 × 20 캔버스를 유지하세요. - Unity UI: Button의 Transition을 Sprite Swap으로 두고, Target Graphic의 Image에
normal.png를, Highlighted Sprite·Pressed Sprite·Disabled Sprite에 hover.png·pressed.png·disabled.png를 넣습니다. - 버튼 크기가 바뀌어야 한다면, 상태에는 테두리가 없으므로 지정하기 전에 9슬라이스 편집기에서 상태 PNG마다 같은 나인 슬라이스 테두리를 주세요.
결과 확인
states.json의 모든 rect가 button-states.png에서 해당 상태를 정확히 잘라 내고, states.hover.ops에 사용한 값이 나열됩니다.normal.png는 원본과 바이트 동일합니다(Firefox에서는 반투명 픽셀이 알파 반올림 한 단계만큼 다를 수 있음).- 게임을 실행해 버튼에 마우스를 올리고, 누르고, 비활성화해 봅니다. 튀는 곳이 없고 pressed는 오프셋만큼만 움직여야 합니다.
문제 해결
| 증상 | 유력한 원인 | 확인 방법 | 해결 |
|---|
| pressed 이미지의 맨 아래 줄이 사라짐 | 1px 오프셋이 같은 캔버스 안에서 픽셀을 옮겨 마지막 줄이 밀려나고 0번 줄은 투명해짐 | pressed.png 아래 가장자리를 원본과 비교 | 그림 아래에 투명한 줄을 하나 남기거나, 오프셋을 0으로 두고 엔진에서 글자를 움직이기 |
|---|
| 포커스된 버튼이 튀거나 겹쳐 보임 | focus.png가 더 크고(40 × 16 버튼이면 44 × 20) Godot는 focus 텍스처를 기본 위에 그림 | states.json → states.focus.size | 외곽선 두께만큼 음수로 옮겨 가운데 맞추거나, 위 설명처럼 링만 남긴 이미지 사용 |
|---|
| 어두운 배경에서 disabled 버튼이 거의 안 보임 | 알파 0.5라 배경이 비쳐 보임 | 흰 바탕이 아닌 실제 배경 위에서 확인 | disabled 알파를 0.7로 올리거나, 알파는 1로 두고 채도만 빼기 |
|---|
| 밝은 버튼에서 hover 차이가 거의 없음 | 밝기는 더하는 방식이라 이미 255에 가까운 채널은 잘림 | 원본 픽셀 값이 약 230 이상 | hover에 밝기 대신 색 덧씌우기나 대비 사용 |
|---|
다른 방법
| 방법 | 이럴 때 더 낫습니다 |
|---|
| Unity Transition = Color Tint | 상태가 색만 다를 때. 이미지가 더 필요 없지만, 색을 곱할 뿐이라 픽셀을 옮기거나(pressed 오프셋) 링을 더할 수 없습니다. |
|---|
| 그림 프로그램에서 상태마다 직접 그리기 | 모양이 달라질 때(뒤집히는 베벨, 바뀌는 아이콘, 빛). 픽셀 계산은 원본에 없는 것을 그릴 수 없습니다. |
|---|
이 방법의 한계
- 상태별 나인 슬라이스 테두리는 없습니다. 9슬라이스 편집기에서 상태 PNG에 주세요.
- 엔진에서 시험하지 않았습니다. 위의 칸 이름은 Godot·Unity 공식 문서에서 가져왔습니다.
버전과 출처
docs/UI-LAB.md를 위해 Chromium에서 40 × 16 버튼으로 측정했습니다. normal은 원본과 바이트 동일, hover는 더 밝고, pressed는 오프셋되며 비워진 줄은 투명, disabled는 알파 128의 회색, focus는 #3182f6 링이 있는 44 × 20이고 그림은 그대로였으며, states.json의 다섯 영역이 스트립에서 각 상태를 정확히 잘라 냈습니다. 위 예시 값은 같은 모듈로 다시 계산했습니다. Godot·Unity 가져오기는 실행하지 않았습니다.
참고한 공식 문서
버튼 상태 만들기
버튼 하나로 기본·호버·누름·비활성·포커스 이미지를 만들고 낱장과 묶음 시트로 저장하세요.
사용 방법
- 이미지 넣기
- 필요한 설정을 조정하고 결과 확인
- 다운로드로 새 파일 저장
지원 형식
PNG / JPG / WebP / AVIF / HEIC → PNG + JSON (ZIP) — 입력 디코딩은 브라우저 지원과 추가 엔진 사용 여부에 따라 다릅니다.
이 도구로 할 수 있는 일
버튼 하나로 기본·호버·누름·비활성·포커스 이미지를 만들고 낱장과 묶음 시트로 저장하세요.
처리 방식과 검증 수준
advanced · brightness, contrast, saturation, overlay, offset and square outline ops / MaxRects strip. 품질 검증을 진행 중입니다. Pro·Flagship 수준은 아직 입증되지 않았습니다.
저장 전에 확인하세요
밝기·대비·채도·색 겹치기·오프셋·외곽선 같은 정해진 픽셀 연산입니다. 없는 그림을 새로 그리지는 않습니다.