---
title: "단 350바이트짜리 5x5 픽셀 폰트 — 작은 화면을 위한 극한 수공예"
published: 2026-04-19T15:19:28.000Z
canonical: https://jeff.news/article/1883
---
# 단 350바이트짜리 5x5 픽셀 폰트 — 작은 화면을 위한 극한 수공예

AVR128DA28 같은 저전력 MCU용 OLED/LCD를 위해 손수 디자인한 5x5 픽셀 폰트 프로젝트. 전체 데이터가 350바이트이며, 5x5가 가독성을 타협하지 않는 최소 크기임을 3x3·2x2까지 실험하며 입증했다.

- 작은 OLED/LCD용으로 **5x5 픽셀 폰트**를 손으로 직접 디자인한 프로젝트
  - 전체 폰트 데이터가 단 **350바이트** — 8비트 MCU(AVR128DA28 같은, RAM 16KB)에 올리기 딱 좋은 크기
  - lcamtuf의 5x6 `font-inline.h`에서 영감 — 그 뿌리는 ZX Spectrum의 8x8 폰트까지 거슬러 올라감

### 왜 5x5가 "가독성 마지노선"인가
- 저자가 더 작게도 다 실험해봄
  - 2x2 — 불가능
  - 3x3 — 이론적으론 가능하나 읽을 수 없음
  - 4x4 — "E", "M", "W"를 제대로 그릴 공간 부족
  - **5x5** — 타협 없이 되는 최소 크기. 대부분의 소문자는 1픽셀 더 작게 그려서 대문자와 시각적으로 구분까지 됨
- 4x5, 3x5도 기술적으론 가능하지만 M, 가운뎃점 0, U/V/Y 구분이 희생됨

### 왜 전부 폭 5로 고정했나
- 예술적 이유는 없음 — **고정폭이 프로그래밍을 훨씬 편하게** 해주기 때문
  - 문자열 길이 = 글자 수 × 6 픽셀 (고정)
  - "8978"이 "1111"보다 길다는 이유로 오버플로우될까 걱정할 필요 없음 → 컴팩트 UI 안전성 확보

### 왜 MCU에 하드코딩 폰트가 필요한가
- 저해상도 384x288 디스플레이도 픽셀 수가 **11만** — AVR 메모리엔 안 들어감
  - 현실적인 선택은 160x128이나 128x64 OLED
  - 이런 디스플레이는 **픽셀 효율 극한으로 짜낸 수제 폰트**가 있어야 제 역할
- 비교 대상으로 벡터 폰트 — 안티에일리어싱, 수 MB 코드, 1MB 폰트 데이터 써도 350바이트 수제품보다 못생김

> [!NOTE]
> 실제 화면에선 픽셀이 완벽한 정사각형이 아니라 서브픽셀 때문에 "유사 드롭섀도우" 효과가 생긴다. 저자는 오히려 이 번짐 덕에 "e"와 "g"가 더 잘 구분된다고 평가.

### 더 작게도 가봄 — 극한의 글리프 실험
- **3x5** — 글리프 조합 32,768개 중 27,904개가 서로 구별됨. M/W/Q가 좀 아쉽지만 O와 0은 구분 가능. 50% 더 많은 열을 화면에 욱여넣을 때 실용적
- **3x4** — 4,096개 중 3,392개 distinct. 대소문자 구분은 포기, 숫자도 타격
- **3x3** — 512개 중 400개 distinct. 숫자 손실 크지만 글자는 중복 없이 그럭저럭 인식 가능
- **2x3** — 64개 중 44개 distinct. 대부분 읽기 불가, 중복 다수. 저자 왈 "여기서 Hello World가 읽힌다고? 농담이지?"
- **3x2** (가로로 뒤집은 2x3) — 의외로 나음. 대부분 글자가 수직보다 수평 디테일이 많기 때문 (M, W, N, Q, G, P 등)
- **2x2** — 16개 이미지 중 빈 칸 1개, 시프트 중복 5개 빼면 10개. 숫자 정도는 되지만 "폰트라기보단 암호 해독표"

---

## 기술 맥락

- 왜 임베디드 개발자들이 이런 수제 비트맵 폰트에 집착하는지 — AVR이나 STM32 같은 8비트/32비트 MCU는 플래시도 RAM도 귀해요. TrueType 렌더러 같은 걸 올리려면 수백 KB가 필요한데, 이 폰트는 350바이트. 즉 LCD에 온도 표시 하나 띄우겠다고 폰트 라이브러리에 용량 다 잡아먹히는 상황을 피하는 거예요
- 고정폭이 왜 그렇게 편한지 — 가변폭 폰트면 커서 위치 계산할 때마다 각 글자 폭을 룩업해야 해요. 고정폭이면 `x = column * 6` 한 줄이면 끝이에요. 인터럽트 루틴이나 게임 루프에서 폰트 렌더링할 때 이 차이가 크거든요. 오버플로우 예측도 쉬워서 "숫자가 갑자기 길어져서 옆 필드 침범"하는 버그가 원천 차단돼요
- 서브픽셀이 폰트를 살리는 현상 — LCD/OLED에서 한 픽셀은 실제로 R/G/B 서브픽셀로 나뉘어 있어요. 작은 폰트에서 이 물리적 틈이 자연스러운 안티에일리어싱처럼 작동해서, 모니터에서 픽셀이 사각형으로 렌더링된 것보다 실제 장치에서 더 부드럽게 보여요. 저해상도 폰트 디자이너들은 이걸 역으로 이용해 "렌더링 미리보기보다 실기기가 예쁘게" 보이도록 설계해요
- C 헤더로 배포하는 이유 — 바이너리 포맷이 아니라 `const uint8_t font[] = {...}` 형태로 주면 컴파일러가 그대로 플래시 섹션에 박아줘요. RAM이 아니라 ROM에 올라가는 거라 귀한 SRAM을 아낄 수 있고, 링커 최적화로 안 쓰는 글리프 제거도 가능해요

## 핵심 포인트

- 전체 폰트 데이터 350바이트, 모든 글자가 5픽셀 정사각형에 들어가고 6x6 그리드에서 안전하게 그려짐
- 4x4 이하에서는 E/M/W를 제대로 표현 못 함 — 5x5가 타협 없는 최소
- 고정폭 선택은 예술이 아닌 프로그래밍 편의 — 문자열 길이 계산이 단순
- lcamtuf의 5x6 font-inline.h에서 영감, ZX Spectrum 8x8 폰트가 뿌리
- 3x5, 3x4, 3x3, 2x3, 3x2, 2x2까지 극한 실험으로 가독성 한계 분석

## 인사이트

저해상도 폰트 디자인은 단순 장식이 아니라 MCU의 RAM/플래시 제약과 서브픽셀 렌더링 물리학을 동시에 고려하는 공학이다. 벡터 폰트 수 MB가 350바이트 수제품에 진다는 점이 본질.
