---
title: "유아용 그림판 만들다가 flood-fill 셀룰러 오토마타를 발견한 이야기"
published: 2026-07-03T03:13:53.000Z
canonical: https://jeff.news/article/4733
---
# 유아용 그림판 만들다가 flood-fill 셀룰러 오토마타를 발견한 이야기

저자는 3살 아이와 함께 쓰기 위한 초단순 협동 그림판 ‘Mr. Baby Paint’를 만들다가, 여러 flood fill이 동시에 자라며 충돌하는 과정에서 새로운 셀룰러 오토마타 같은 패턴을 발견했다. 글은 유아용 UX 설계, CPU 기반 flood fill의 의도적 느림, Catmull-Rom spline 브러시, 비트맵 폰트 굵게 만들기 실험까지 꽤 알찬 제작기를 담고 있다.

## 아이가 ‘망칠 수 없는’ 그림판 만들기

- 저자는 3살 아이와 같이 쓰려고 Mr. Baby Paint라는 그림 앱을 만들었음
  - 아이는 키보드 누르기, 마우스 흔들기, 휠 돌리기 자체는 좋아함
  - 하지만 Wordpad나 MS Paint는 메뉴·툴바·작업표시줄을 잘못 누르는 순간 부모가 계속 개입해야 했음
  - 아이 입장에서는 그 끊김이 제일 짜증나는 부분이었음

- 그래서 목표는 극단적으로 단순한 협동 그림판이 됨
  - 전체 화면은 빈 캔버스
  - 메뉴와 툴바는 없음
  - 아이는 마우스를 움직이고, 보호자는 키보드 단축키로 저장·지우기·기능 전환을 맡음
  - 어떤 행동을 해도 그림, 소리, 시각 효과 중 하나는 나오게 설계함

- 입력 방식도 아이의 불규칙한 움직임을 UX의 일부로 받아들임
  - 왼쪽 클릭은 그리기
  - 오른쪽 클릭이나 단축키는 채우기
  - 마우스 휠이나 Enter는 모래 뿌리기
  - 빠르게 그릴수록 페인트가 더 튐

- 화면 가장자리는 설정 패널처럼 동작함
  - 왼쪽 가장자리 16구간은 브러시 크기와 폰트 선택
  - 아래쪽 16구간은 색상 선택
  - 위쪽 64구간은 문자 선택
  - 오른쪽은 원형 브러시와 사각 브러시 선택
  - 정밀한 클릭 대신, 어차피 아이가 화면 끝을 자주 건드린다는 점을 활용한 셈임

> [!TIP]
> 유아용 UX의 핵심은 기능을 줄이는 게 아니라, 잘못된 입력이라는 개념을 없애는 쪽에 가까움. 이 앱은 랜덤 입력을 실패가 아니라 놀이 재료로 바꿔버림.

## 빠른 마우스 움직임을 선으로 만드는 문제

- 일반 마우스 입력은 연속 곡선이 아니라 몇 밀리초마다 찍힌 점들의 목록임
  - 보통 그림 앱은 점과 점 사이를 직선으로 이어서 선을 만듦
  - 적당히 빠른 움직임에서는 이걸로 충분함
  - 하지만 유아의 마우스 움직임은 점 간격이 수십~수백 픽셀까지 벌어질 수 있음

- 저자는 Catmull-Rom spline으로 점들을 부드럽게 이었음
  - 점 사이를 각진 직선이 아니라 매끄러운 곡선으로 보간함
  - 그 곡선을 따라 1px 간격으로 브러시 텍스처를 찍음
  - 큰 브러시에서는 이 방식이 느려져서 스탬핑 거리 제한을 둬야 했음

- 이건 단순 그래픽 문제가 아니라 앱의 사용자를 정확히 반영한 결정임
  - 성인용 드로잉 앱이라면 평범한 보간으로 충분했을 수 있음
  - 여기서는 사용자가 ‘마우스를 통제 못 하는 사람’이라서 입력 처리 자체가 제품 경험의 핵심이 됨

## flood fill 버그가 놀이가 되다

- 페인트통 도구는 Mario Paint처럼 천천히 차오르게 만들었음
  - 대부분의 앱은 fill을 즉시 끝냄
  - Mario Paint는 채워지는 과정을 보여줘서 보는 재미가 있음
  - Mr. Baby Paint는 위아래뿐 아니라 좌우로도 fill이 자라게 했음

- 저자는 fill이 끝날 때까지 다른 행동을 막고 싶지 않았음
  - 아이용 앱에서 기다림은 재미를 끊는 요소임
  - 그래서 여러 flood fill과 그리기가 동시에 일어나도록 만들었음
  - 여기서 예상 못 한 패턴이 터짐

- 여러 fill이 같은 성장 예산을 공유하면서 셀룰러 오토마타 같은 동작이 생김
  - 전체 flood fill 성장은 프레임당 1000픽셀로 제한됨
  - 새 fill은 크기가 작아서 기존 fill보다 더 빨리 자람
  - 새 fill을 기존 fill의 안쪽 가장자리 근처에 찍으면 서로 충돌하면서 유기적인 패턴이 생김
  - 같은 색과 다른 색의 fill들이 무너지듯 합쳐지고, 물결치고, 때로는 수천 세대 동안 반안정 상태로 감

- GPU 버전도 만들었지만 일부러 CPU 단일 스레드 방식을 남겼음
  - compute shader 버전은 빠르고 랙이 거의 없음
  - 그런데 결과가 덜 재미있었다고 함
  - CPU 순차 계산의 느림과 순서성이 이 오토마타가 작동하는 조건이었기 때문임

> [!IMPORTANT]
> 이 사례에서 성능 최적화는 무조건 정답이 아니었음. 빠른 GPU 구현보다 느린 CPU 구현이 더 재미있는 상호작용을 만들었고, 저자는 그 느림을 디자인 선택으로 남김.

```mermaid
sequenceDiagram
    participant 아이입력
    participant 캔버스
    participant 채우기엔진
    participant 기존채우기
    participant 새채우기
    아이입력->>캔버스: 여러 위치에 fill 시작
    캔버스->>채우기엔진: 동시 flood fill 등록
    채우기엔진->>기존채우기: 프레임당 성장 예산 배분
    채우기엔진->>새채우기: 작은 fill이 더 빠르게 성장
    새채우기->>기존채우기: 가장자리에서 충돌
    기존채우기->>캔버스: 진동하거나 한쪽이 사라지는 패턴 생성
```

## 비트맵 폰트 굵게 만들기 삽질

- Mr. Baby Paint에는 16개 폰트가 들어감
  - 오래된 컴퓨터 폰트는 Rob Hagemans의 Hoard of bitfonts에서 가져옴
  - 직접 만든 폰트도 넣고 싶어서 기존 single stroke font editor를 활용함
  - 문제는 1px 스트로크가 너무 얇았다는 점임

- 단순히 검은 픽셀마다 큰 사각형을 찍는 방식은 바로 한계가 드러남
  - 글자 안쪽 디테일이 뭉개짐
  - 획 사이의 중요한 틈이 사라짐
  - 전체적으로 투박하고 답답해짐

- 그래서 저자는 거의 알고리즘 실험장을 열었음
  - JFA distance field와 second-nearest component distance
  - angular gap detection
  - white-space skeleton 감지
  - adaptive per-pixel radius
  - SDF와 16방향 ray-casting
  - Meijster exact Euclidean distance transform
  - iterative dilation과 collision detection
  - topology-preserving dilation

- 최종 선택은 4번째 방식에 가까웠음
  - JFA distance field와 white-space skeleton 기반으로 틈을 보존하는 접근임
  - 완벽하진 않아서 Aseprite에서 수동 보정함
  - 결과적으로 같은 skeleton에서 다른 굵기와 스타일을 뽑아내는 비트맵 폰트 파이프라인을 얻음

## 작지만 실제로 출시한 제품

- Mr. Baby Paint는 Mac, Windows, Linux용으로 itch.io에 올라갔음
  - 가격은 4.99달러
  - 글 작성 시점 기준 약 30개가 팔렸다고 함
  - 저자에게는 처음 판매해본 앱이기도 함

- 이 글이 재밌는 이유는 결과물보다 과정에 있음
  - 유아용 앱이라는 제약이 입력 처리, UI, 알고리즘 선택까지 전부 바꿨음
  - 우연히 생긴 glitch를 버그로 지우지 않고 핵심 재미로 남김
  - 폰트 굵게 만들기 같은 사이드 퀘스트도 끝까지 파고들어 실제 파이프라인으로 만들었음

---

## 기술 맥락

- 이 앱의 가장 큰 기술 선택은 “정확한 입력을 요구하지 않는 인터페이스”예요. 사용자가 세 살 아이이기 때문에 버튼을 잘 누르게 만드는 게 아니라, 아무 데나 움직이고 눌러도 의미 있는 결과가 나오게 만드는 쪽이 맞았던 거죠.

- Catmull-Rom spline을 쓴 것도 같은 이유예요. 일반 앱에서는 마우스 좌표 사이를 직선으로 이어도 충분하지만, 여기서는 좌표 간격이 수백 픽셀까지 튈 수 있어요. 그래서 입력을 그대로 믿지 않고, 사용자의 움직임을 그럴듯한 곡선으로 재구성해야 했어요.

- flood fill을 CPU 단일 스레드로 남긴 결정은 특히 재밌어요. GPU compute shader로 옮기면 성능은 좋아지지만, 순차 처리와 제한된 성장 예산에서 생기는 충돌 패턴이 사라져요. 이 경우 느림은 결함이 아니라 장난감의 물리 법칙이 된 셈이에요.

- 비트맵 폰트 굵게 만들기에서도 단순 dilation 대신 거리장, gap detection, skeleton 같은 방법을 계속 시험한 이유가 있어요. 작은 글자는 획을 키우는 순간 내부 공간이 쉽게 막히기 때문에, “굵게”와 “읽힘” 사이의 균형을 알고리즘으로 잡아야 하거든요.

- 전체적으로 보면 이 프로젝트는 기능 목록보다 제약 조건이 설계를 이끈 사례예요. 아이의 불규칙한 입력, 실시간 시각 피드백, 느린 fill의 재미, 픽셀 폰트의 가독성이 서로 얽히면서 일반 그림판과 완전히 다른 기술 판단을 만들었어요.

## 핵심 포인트

- Mr. Baby Paint는 메뉴와 툴바 없이 전체 화면을 캔버스로 쓰는 유아용 협동 그림 앱이다
- 빠르고 불규칙한 마우스 움직임을 부드럽게 잇기 위해 Catmull-Rom spline과 1px 간격 브러시 스탬핑을 썼다
- 여러 flood fill이 1000픽셀/frame 성장 예산을 공유하면서 충돌해 유기적인 패턴을 만드는 셀룰러 오토마타가 생겼다
- GPU compute shader 버전은 빠르지만 재미가 덜해서, CPU 단일 스레드의 느림을 일부러 디자인 요소로 남겼다
- 비트맵 폰트를 굵게 만들기 위해 JFA, SDF, ray-casting, dilation 등 여러 알고리즘을 실험했고 최종적으로 수동 보정까지 거쳤다

## 인사이트

이 글은 ‘아이용 앱’이라는 귀여운 포장 안에 꽤 진지한 인터랙션 설계와 그래픽 알고리즘 삽질이 들어 있다. 특히 버그처럼 보이는 flood fill 충돌을 제거하지 않고 놀이의 핵심으로 남긴 판단이 좋다.
