TRENDSHIFT DAILY #12 · 2026-07-25 · DRAW-YOUR-FONT · 손글씨 사진 → 진짜 폰트

draw-your-font 딥다이브
— 종이에 쓴 손글씨를 사진 한 장으로 설치 가능한 진짜 폰트로 바꾸는 도구

draw-your-font은 종이에 알파벳을 손으로 쓰고 사진 한 장만 찍으면, 컴퓨터에 설치해서 쓸 수 있는 진짜 폰트 파일(TTF · WOFF · WOFF2)을 만들어 주는 오픈소스 도구다. 한 문장으로 말하면 "내 손글씨를 재사용 가능한 도장(폰트)으로 새겨 주는 작은 폰트 공장"이다.

이 프로젝트의 급소는 두 가지다. 하나, 손글씨 사진이 내 기기를 절대 벗어나지 않는다. 서버 업로드도, 계정도, 유료 크레딧도 없이 전부 내 컴퓨터(혹은 내 브라우저) 안에서 돈다. 둘, AI는 글자를 "그리지" 않는다. 사진에서 글자를 찾고·이름표를 붙이고·결과를 심사만 하고, 실제 곡선·좌표·폰트 조립 같은 기하 연산은 전부 결정론적인 코드가 한다.

(저장소 danilo-znamerovszkij/draw-your-font · 언어 순수 JavaScript(CommonJS) · 핵심 엔진 sharp + potrace + svg2ttf · 3중 배포 npm CLI · Claude Code 스킬 · 브라우저 데모 · 라이선스 MIT · 분석 시점 v0.1.0 (최신 커밋 2026-07-24) · shallow clone 소스 직접 분석)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 주목받는가 — 바이너리 0개 · 로컬 · AI 역할 분리
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석 — 6단계 파이프라인
  5. 디렉토리 구조 해부
  6. 학습 포인트
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

"내 글씨체로 타이핑하고 싶다"는 오랜 로망을, 사진 한 장으로

손으로 쓴 글씨를 컴퓨터 폰트로 만들고 싶다는 욕망은 오래됐다. 문제는 그 과정이 늘 번거로웠다는 것이다. 전문 폰트 편집기(FontForge)를 배우거나, 유료 웹서비스(Calligraphr 같은)에 손글씨를 업로드하고 월 구독료를 내야 했다. draw-your-font은 이 장벽을 걷어낸다. 알파벳을 종이에 한 번 쓰고, 스마트폰으로 사진을 찍어 그 파일을 도구에 넘기면 끝이다.

이 도구는 세 가지 얼굴을 가진다. (1) 터미널에서 명령 한 줄로 돌리는 npm CLI, (2) Claude 같은 AI 에이전트와 대화하며 만드는 Claude Code 스킬, (3) 아무것도 설치하지 않고 웹페이지에서 바로 돌아가는 100% 브라우저 데모. 세 얼굴이 같은 핵심 코드를 공유한다 — 파일을 읽는 방식만 다를 뿐, 사진을 폰트로 바꾸는 계산은 동일하다.

핵심 비유

"매번 손으로 쓰는 사람" vs "도장(印) 하나를 판 사람"

편지에 내 글씨체를 쓰고 싶을 때, 예전에는 글자를 매번 하나하나 손으로 써야 했다. 같은 'ㄱ'도 쓸 때마다 조금씩 달라지고, 시간도 든다.

draw-your-font은 도장 장인과 같다. 내 손글씨를 딱 한 번 건네주면, 그걸 재사용 가능한 도장(폰트)으로 새겨 준다. 이제 키보드로 타이핑만 하면 어디서든 내 손글씨가 찍힌다. 게다가 그 새김 작업이 가게에 맡겨지지 않고 내 책상 위에서 일어난다 — 손글씨 원본이 밖으로 나가지 않는다.

기술적으로 이 도구가 하는 일은 "이미지 처리 + 벡터화 + 타이포그래피 조립"의 결합이다. 사진에서 잉크를 배경과 분리하고(§4-①), 글자 덩어리를 하나씩 오려내고(②), 각 글자에 이름표를 붙이고(③), 비트맵을 매끄러운 벡터 곡선으로 바꾸고(④~⑤), 마지막으로 그 곡선들을 공유된 좌표계에 맞춰 진짜 폰트 파일로 조립한다(⑥). 이 여섯 단계가 이 문서의 뼈대다.

용어 풀이
벡터화 (vectorization / tracing)
사진 속 글자는 점(픽셀)의 모음이다. 이걸 그대로 폰트로 쓰면 확대할 때 계단처럼 깨진다. 벡터화는 픽셀 덩어리의 윤곽선을 수학 곡선(베지어 곡선)으로 따내는 작업이다. 곡선은 아무리 확대해도 매끄럽다. 폰트가 어떤 크기에서도 선명한 이유가 바로 이 벡터 형식 덕분이다. draw-your-font은 potrace라는 엔진으로 이 일을 한다.

2왜 주목받는가 — 바이너리 0개 · 로컬 · AI 역할 분리

TrendShift Daily 상위권(#12)에 오른 이유 4가지

손글씨-폰트 변환 도구는 예전에도 있었다. 그런데 draw-your-font이 트렌딩에 오른 건 접근 방식이 확실히 다르기 때문이다. 네 가지 결이 겹친다.

① 네이티브 바이너리 0개 — 순수 npm + WASM만으로

기존 손글씨-폰트 파이프라인의 가장 큰 진입장벽은 시스템 의존성이었다. FontForge를 깔고, ImageMagick을 깔고, potrace 바이너리를 PATH에 넣고… OS마다 설치법이 달라 초보자는 시작조차 어려웠다. draw-your-font은 이 모든 네이티브 바이너리를 전부 npm 패키지와 WebAssembly로 대체했다. Node.js 18 이상만 있으면 macOS·Linux·Windows 어디서든 npx 한 줄로 돈다. 설치할 "프로그램"이 없다.

② 프라이버시 + 무료 — 손글씨가 기기를 안 떠난다

README가 직접 겨냥하는 경쟁자는 Calligraphr($8/월)다. draw-your-font의 포지셔닝은 명확하다. "그들의 비용은 서버와 브라우저 편집기다. 여기선 네 기계가 그 일을 하고, AI 에이전트가 편집기 역할을 한다." 손글씨 사진은 어떤 서버에도 올라가지 않는다. 계정 생성도, 업로드도, 구독료도 없다. 내 필체라는 민감한 개인 데이터가 온전히 내 손 안에 남는다.

③ AI 역할 분리 — "AI는 그리지 않는다. 보고, 이름 붙이고, 심사만 한다"

이 프로젝트에서 가장 신선한 설계 사상이다. AI(Claude 비전)는 폰트의 곡선을 단 한 점도 그리지 않는다. AI가 하는 일은 딱 셋 — 사진 속 글자 덩어리를 찾고(find), 각 덩어리에 "이건 A, 이건 B"라고 라벨(label)을 붙이고, 완성된 프리뷰를 아트디렉터처럼 심사(judge)한다. 실제 좌표·곡선·메트릭·폰트 조립은 전부 결정론적인 코드가 계산한다. "AI는 지각과 판단, 코드는 기하와 계산"이라는 역할 분리가 결과의 일관성과 재현성을 만든다.

④ 타이포그래피 "craft" — 스티커 모음이 아니라 진짜 폰트

손글씨 글자를 그냥 하나씩 오려 붙이면 크기·높낮이가 제각각인 스티커 모음이 된다. 진짜 폰트처럼 보이려면 모든 글자가 같은 좌표계(공유 em-square) 안에서 자기 자리를 지켜야 한다 — 'g'는 baseline 아래로 내려가고, 소문자 'o'는 대문자보다 작게. draw-your-font은 이 타이포그래피 디테일(§4-③)을 코드로 강제한다. 단순 소개용 장난감이 아니라, 폰트를 "폰트답게" 만드는 craft가 들어 있다는 점이 개발자들의 눈길을 끌었다. 게다가 이 모든 게 브라우저에서도 완전히 동일하게 돌아간다.

한 걸음 더 — 왜 "역할 분리"가 영리한가

만약 AI에게 "이 손글씨로 폰트를 그려 줘"라고 통째로 맡기면, 매번 결과가 달라지고(비결정성) 곡선이 미묘하게 뒤틀린다. draw-your-font은 AI가 잘하는 일("이 흐릿한 덩어리가 알파벳 e구나"라고 알아보기)과 코드가 잘하는 일(정확한 좌표 계산·곡선 추출)을 칼같이 나눴다. 그래서 같은 사진은 항상 같은 폰트를 만든다. 이건 "LLM을 어디에 쓰고 어디에 안 쓸지"를 잘 판단한 좋은 엔지니어링 사례다.

구분전형적 손글씨-폰트 서비스draw-your-font
설치FontForge·ImageMagick 등 네이티브 툴없음 — Node 18 + npm만 (바이너리 0개)
입력 방식서버에 스캔본 업로드로컬 사진 파일 (업로드 없음)
비용월 구독(예: Calligraphr $8/월)무료 · MIT 오픈소스
프라이버시손글씨가 서버로 전송기기를 벗어나지 않음
AI 역할대개 없음(수동 정렬) 또는 블랙박스찾기·라벨·심사만, 기하는 코드가
실행 위치웹 브라우저(그 회사 서버)CLI · AI 스킬 · 내 브라우저 3중

3기술 스택 전체 지도

빌드 스텝 없는 순수 JavaScript — 의존성 7개로 폰트 공장을 짓다

코드를 열면 놀라운 점이 두 가지다. 첫째, TypeScript도 빌드 도구도 없다. 순수 JavaScript(CommonJS require)로 작성돼 node가 바로 실행한다(브라우저 데모 번들만 예외). 둘째, 전체 코어가 약 990줄, src/ 12개 모듈뿐이다. 무거운 프레임워크 없이, 잘 고른 npm 패키지 7개를 파이프처럼 이어붙여 폰트 공장을 만든다.

package.json — 핵심 의존성과 각자의 역할

패키지버전파이프라인에서의 역할
sharp^0.33libvips 기반 이미지 처리. grayscale·정규화·리사이즈·median·모폴로지·합성 — 캡처/세그먼트/프리뷰 렌더 전부를 담당하는 일꾼
potrace^2.1비트맵 → SVG 벡터화. FontForge·Inkscape 내부와 같은 알고리즘의 순수 JS 포트
svg2ttf^6.0직접 저작한 SVG-font XML → TTF 바이너리로 변환
ttf2woff^3.0TTF → WOFF (웹폰트 포맷)
wawoff2^2.0TTF → WOFF2 (WASM 기반 압축기, 가장 작은 웹폰트)
svgpath^2.6SVG path 변환(이동·스케일·반올림)과 파싱
pdfkit^0.15A4 손글씨 템플릿 PDF 생성(가이드 셀이 그려진 연습지)

개발용 의존성(devDependencies)도 성격이 뚜렷하다. esbuild는 브라우저 데모를 하나의 IIFE 번들로 묶고, esm-potrace-wasm은 브라우저에서 쓸 WASM 버전 potrace를 제공하며, opentype.js는 테스트에서 완성된 폰트를 거꾸로 파싱해 메트릭·와인딩이 맞는지 검증하는 데 쓴다.

영역선택왜 이렇게 했나
언어순수 JavaScript (CommonJS)빌드 스텝 없이 node가 바로 실행. 진입장벽 최소화
이미지 엔진sharp (libvips)ImageMagick 같은 네이티브 툴 없이 npm 프리빌트 바이너리로 고속 처리
벡터화potrace (JS 포트)네이티브 potrace 바이너리 불필요. 브라우저에선 WASM 버전으로 동일 동작
폰트 조립SVG-font 직접 저작 → svg2ttf아이콘폰트 툴의 "자동 정규화"가 메트릭을 건드리지 못하게 XML을 손으로 작성
프론트/데모바닐라 HTML/CSS/JS + esbuild저자 손글씨 폰트로 꾸민 랜딩 + 100% 클라이언트 실행 데모
배포GitHub Actions → GitHub Pagessite/** 변경 시에만 트리거되는 자동 정적 배포
용어 풀이
WASM (WebAssembly)
C·Rust 같은 언어로 짠 프로그램을 브라우저·Node에서 거의 네이티브 속도로 돌리게 해주는 이식 가능한 바이너리 포맷. draw-your-font은 potrace(벡터화)와 wawoff2(WOFF2 압축) 같은 무거운 계산을 WASM으로 처리해서, 사용자가 별도 프로그램을 깔지 않아도 되게 만든다. "네이티브 툴의 성능을 npm 패키지 안으로 가져오는" 열쇠다.
용어 풀이
sharp / libvips
sharp는 Node.js에서 가장 빠른 이미지 처리 라이브러리로, 내부적으로 libvips라는 저메모리 이미지 엔진을 쓴다. 이 도구에선 사진을 흑백으로 바꾸고, 밝기를 정규화하고, 잉크와 배경을 가르고, 노이즈를 지우는 모든 픽셀 작업을 sharp가 담당한다. 설치 시 OS에 맞는 프리빌트 바이너리가 자동으로 딸려와, 사용자가 C 컴파일러를 만질 일이 없다.

4아키텍처 심화 분석 — 6단계 파이프라인

사진 → 잉크 마스크 → 글자 오리기 → 라벨 → 벡터화 → 조립

전체 흐름은 "사진 한 장이 여섯 개의 작업대를 차례로 통과하는 컨베이어 벨트"로 그릴 수 있다. 각 작업대는 앞 단계의 산출물을 받아 다음 단계가 쓸 형태로 다듬는다.

사진(jpg/png) │ ▼ ① capture.js — 적응형 이진화(잉크 vs 배경 가르기) [ 잉크 마스크 (흑백) ] │ ▼ ② segment.js + blob-core.js — 연결요소로 글자 덩어리 오리기 [ crop 조각들 + 컨택트 시트 + blobs.json ] │ ▼ ③ 라벨링 — "이 덩어리는 A" 매핑 (Claude 비전 · 사용자 · 템플릿 순서) [ 덩어리 → 문자 매핑 ] │ ▼ ④ trace.js — potrace로 비트맵 → SVG 곡선 (+ 굵기 조절) [ 각 글자의 SVG path ] │ ▼ ⑤ metrics.js + winding.js — 공유 em-square 배치 + 와인딩 교정 [ 폰트 좌표계에 정렬된 글리프 ] │ ▼ ⑥ assemble.js — SVG-font 저작 → TTF → WOFF → WOFF2 (+ CSS) [ 설치 가능한 폰트 파일 3종 + preview.png ] ※ ①~⑥ 중 ①(capture)만 브라우저에서 Canvas로 재구현. 나머지는 Node·브라우저 공유 코드.

① 관심사 분리 — "AI는 보고, 코드는 계산한다"

스킬(SKILL.md)이 지휘자 역할을 한다. 세그먼트를 돌리고 → 컨택트 시트(오려낸 글자들을 한 장에 모은 이미지)를 비전으로 판독해 라벨을 붙이고 → 프리뷰를 아트디렉터처럼 심사하고 → 필요하면 굵기·매끄러움을 조절해 다시 만든다. 하지만 좌표나 SVG는 절대 손대지 않는다. 결정론적 CLI가 단일 진실원(source of truth)이다.

② 순수 기하 코어 공유 — Node와 브라우저가 같은 코드를 쓴다

blob-core.js·metrics.js·winding.js·assemble.js는 파일시스템(fs)이나 sharp전혀 의존하지 않는 순수 함수다. 덕분에 Node CLI와 브라우저 데모가 이 코어를 글자 하나 안 바꾸고 그대로 재사용한다. 브라우저 데모는 사진을 읽는 capture 단계만 Canvas API로 다시 구현하면 됐다. "플랫폼에 의존하는 I/O"와 "순수 계산"을 분리한 전형적 설계다.

③ 공유 em-square 메트릭 = "craft"의 핵심 (metrics.js)

이 파일이 폰트를 "폰트답게" 만드는 급소다. 각 글자를 따로따로 정규화하지 않고, 모든 문자가 공유하는 1000 UPM(units per em) 좌표계 안에서 자기 수직 밴드를 갖는다. 예를 들어 대문자 높이(cap height) 700, 소문자 x-높이(x-height) 480, 아래로 내려가는 부분(descender) −220, 위로 올라가는 부분(ascender) 720. placeGlyph 함수가 오려낸 잉크를 해당 밴드에 균일 스케일로 앉히고, y축을 뒤집는다(사진은 아래로 y+ 증가, 폰트는 위로 y+ 증가). 사이드베어링(글자 좌우 여백)과 advance width(다음 글자까지 나아갈 폭)도 여기서 계산한다.

비유 — em-square는 합창단의 오선지다

글자를 하나씩 오려 붙이기만 하면, 크기와 높낮이가 제멋대로인 사진 콜라주가 된다. 공유 em-square는 합창단이 함께 보는 오선지 같다. 모두가 같은 기준선(baseline)과 높이 규칙을 지키기 때문에, 'g'는 선 아래로 꼬리를 내리고 'o'는 대문자보다 작게 자리 잡는다. 이 공통 규칙이 낱장의 글자들을 하나의 "폰트"로 묶는다.

④ nonzero 와인딩 교정 (winding.js)

글자 'o'·'b'·'g'·'a'에는 속이 빈 구멍(bowl)이 있다. 그런데 potrace는 모든 윤곽선을 같은 방향으로 뱉기 때문에, 그대로 폰트로 만들면 이 구멍들이 까맣게 메워진다. TrueType 폰트는 "nonzero winding" 규칙을 쓰는데, 이는 바깥 윤곽과 안쪽 구멍의 회전 방향이 서로 반대여야 한다는 뜻이다. winding.js는 각 서브패스의 부호 있는 넓이(signed area)와 점-다각형 포함 검사(point-in-polygon)로 중첩 깊이를 계산해, 짝수 깊이는 시계 방향·홀수 깊이는 반시계 방향으로 다시 배향한다. 곡선을 뒤집을 때 베지어 제어점도 올바르게 스왑한다.

// winding.js — 왜 이게 필요한가 (개념)
potrace 출력:  바깥선 ↻   안쪽 구멍 ↻   (같은 방향 → 구멍이 메워짐)
교정 후:       바깥선 ↻   안쪽 구멍 ↺   (반대 방향 → 구멍이 뚫림)

// 중첩 깊이로 방향 결정
depth 0 (바깥)  → 시계방향(CW)
depth 1 (구멍)  → 반시계방향(CCW)
depth 2 (섬)    → 다시 CW ...

⑤ 폰트를 직접 저작한다 (assemble.js)

마지막 조립 단계에서, 이 도구는 SVG-font XML을 문자열로 직접 작성한다. 아이콘폰트 변환 도구들이 흔히 하는 "자동 정규화(normalize)"가 §4-③에서 공들여 맞춘 메트릭을 다시 헝클어뜨리지 못하게 하려는 의도적 선택이다. 이렇게 손으로 만든 SVG-font를 svg2ttf에 넣어 TTF를 얻고, 거기서 WOFF·WOFF2와 @font-face CSS까지 파생시킨다.

// assemble.js가 직접 써 내려가는 SVG-font 뼈대 (태그는 예시)
<font horiz-adv-x="...">
  <font-face units-per-em="1000" ascent="720" descent="-220"/>
  <missing-glyph />
  <glyph unicode="A" horiz-adv-x="..." d="M..."/>
  <glyph unicode="b" horiz-adv-x="..." d="M..."/>
</font>
// → svg2ttf → TTF → ttf2woff → WOFF → wawoff2 → WOFF2
// → @font-face CSS 스니펫까지 자동 생성

⑥ 템플릿의 영리한 잉크 트릭 (template.js)

pdfkit으로 만드는 A4 연습지에는 글자를 쓸 칸과 가이드선이 있다. 그런데 이 가이드선을 옅은 회색(#c8c8c8)으로 인쇄한다. 왜? ①단계 캡처의 이진화 임계값이 이 옅은 회색을 배경으로 판정해 지워버리기 때문이다. 결과적으로 사용자가 펜으로 쓴 진한 잉크만 살아남는다. 게다가 칸 순서가 곧 문자셋 순서라서, 글자를 인식하지 않고도 "3번째 칸 = C"처럼 라벨이 자동으로 정해진다.

잘 만든 지점
딥러닝 모델 0개 — 고전 컴퓨터비전만으로

이 파이프라인 어디에도 학습된 신경망이 없다. 잉크 분리는 적응형 임계화, 글자 오리기는 연결요소 라벨링(flood fill), 노이즈 제거는 모폴로지 연산 — 전부 수십 년 검증된 고전 CV 기법이다. AI(비전)는 오직 "이 덩어리가 무슨 글자인지" 알아보는 데만 쓴다. 무겁고 비결정적인 딥러닝을 꼭 필요한 곳에만 최소로 투입한 절제가 돋보인다.

5디렉토리 구조 해부

src/ 12개 모듈 · 스킬 레이어 · 브라우저 데모 세 갈래

구조는 세 덩어리로 나뉜다. 핵심 파이프라인(src/), AI 스킬 레이어(skills/), 랜딩+브라우저 데모(site/). 각각 "엔진 · 대화형 껍데기 · 웹 쇼케이스"에 해당한다.

draw-your-font/ ├─ src/ ★ 핵심 파이프라인 (12개 모듈, 약 990줄) │ ├─ cli.js 진입점: template/segment/build/make/preview 명령 (210줄) │ ├─ index.js 라이브러리 진입점 — 전 모듈 re-export │ ├─ capture.js ① 사진 → 잉크 마스크 (적응형 임계 + 모폴로지) │ ├─ blob-core.js ② 순수 기하: 연결요소·조각 병합·읽기 순서 (Node+브라우저 공유) │ ├─ segment.js ② 잉크 마스크 → crop PNG + 컨택트 시트 + blobs.json │ ├─ trace.js ④ crop → SVG path (potrace) + 굵기 조절 │ ├─ metrics.js ⑤ ★ 공유 em-square 밴드 배치 (craft의 핵심) │ ├─ winding.js ⑤ nonzero 와인딩 교정 (구멍 뚫기) │ ├─ assemble.js ⑥ SVG-font 저작 → TTF/WOFF/WOFF2/CSS │ ├─ preview.js 벡터에서 바로 PNG 프리뷰 렌더 (래스터라이저 불필요) │ ├─ template.js A4 연습지 PDF 생성 (pdfkit, 옅은 회색 가이드) │ └─ charsets.js 문자셋 정의 (minimal / spanish) ├─ skills/draw-your-font/ ★ Claude Code 스킬 레이어 │ ├─ SKILL.md 대화형 지침 (플로우·심사·리파인·가독성 리포트) │ ├─ scripts/resolve-cli.js CLI 위치 해석 (모노레포/글로벌/npx) │ └─ references/troubleshooting.md 증상 → 처방 가이드 ├─ site/ ★ GitHub Pages 랜딩 + 100% 클라이언트 데모 │ ├─ index.html, demo.src.js(원본), demo.js(esbuild 번들) │ └─ DansHand.woff2(저자 손글씨 폰트), hero.png, draw_your_font.mp4 ├─ test/e2e.js 합성 손글씨 → 폰트 → opentype.js 역검증 ├─ .github/workflows/pages.yml Pages 자동 배포 └─ package.json, README.md, LICENSE(MIT)
읽는 순서 팁

이 레포를 처음 연다면 cli.js(전체 흐름) → capture.js(사진 해석) → blob-core.js(글자 오리기) → metrics.js(폰트 좌표계) → assemble.js(최종 조립) 순서를 추천한다. "입력을 어떻게 받고 → 잉크를 어떻게 찾고 → 글자를 어떻게 나누고 → 어떤 좌표에 앉히고 → 어떻게 파일로 뽑는가"를 컨베이어 순서대로 따라가면, 990줄짜리 파이프라인이 한눈에 들어온다. winding.js는 "폰트 구멍은 왜 뚫려 있나"의 독립 교재로, metrics.js는 "타이포그래피 좌표계란 무엇인가"의 교재로 따로 읽어도 좋다.

6학습 포인트

이 저장소 하나로 배울 수 있는 기술의 스펙트럼

draw-your-font의 매력은 "손글씨 폰트"라는 주제를 걷어내도 남는다. 이미지 처리 · 컴퓨터비전 · 타이포그래피 · 폰트 엔지니어링 · 크로스플랫폼 코드 설계 · AI 에이전트 스킬 설계가 한 레포에 응축돼 있다.

① sharp/libvips로 하는 실전 이미지 처리

capture.js는 이미지 처리의 축소판이다. EXIF 회전 정보 존중, 밝기 정규화, 로컬 배경 추정(이미지를 1/32로 줄여 blur한 뒤 다시 키워 "그림자 지도"를 만들고, 그보다 어두운 픽셀만 잉크로 판정)으로 조명 얼룩·그림자에 강한 적응형 임계화를 구현한다. 여기에 median 필터로 speckle(점 노이즈)을 지우고, 직접 짠 4-이웃 모폴로지(grow/shrink)로 끊긴 획을 잇는다. "완벽하지 않은 실제 사진"을 다루는 기법의 보고다.

② 연결요소 라벨링 — 재귀 대신 명시적 스택

blob-core.js는 잉크 마스크에서 "서로 붙어 있는 픽셀 덩어리"를 하나의 글자로 묶는다(8방향 flood fill). 핵심 교훈: 재귀로 짜면 큰 이미지에서 스택 오버플로가 난다. 그래서 Int32Array 기반 명시적 스택으로 순회하며, bounding box와 면적을 동시에 집계한다. i의 점, 콜론, 따옴표처럼 떨어진 조각mergeParts가 다시 합치는데, 매 라운드 median 높이를 재계산해 그림자 speck 무리가 기준을 오염시키지 못하게 막는다.

③ 타이포그래피의 기초 문법

metrics.js를 이해하면 "폰트가 왜 폰트처럼 보이는가"를 알게 된다. UPM(units per em), ascent/descent, cap height, x-height, descender, 사이드베어링(lsb/rsb), advance width — 이 용어들이 실제 좌표로 어떻게 구현되는지 코드로 배운다. 타이포그래피 이론서를 읽는 것보다 이 79줄이 더 빠르다.

④ 와인딩 규칙 — 벡터 그래픽스의 숨은 규칙

winding.js는 "왜 글자 구멍이 뚫려 있는가"라는, 평소 당연하게 여기던 것의 이면을 보여준다. nonzero vs even-odd 규칙, 부호 있는 넓이(신발끈 공식), 점-다각형 포함 검사(ray casting), 베지어 곡선 역순화 — 벡터 그래픽스를 다루는 누구에게나 유용한 기초다.

⑤ 폰트 포맷 파이프라인

SVG-font → TTF → WOFF → WOFF2로 이어지는 변환 사슬을 직접 본다. 각 포맷의 매직 바이트(wOFF, wOF2), 왜 웹에선 WOFF2를 쓰는지(압축률), @font-face CSS가 폰트를 어떻게 브라우저에 등록하는지까지 한 번에 익힌다.

⑥ Node ↔ 브라우저 코드 공유 설계

같은 metrics.js·winding.js·assemble.js가 서버(Node)와 브라우저 양쪽에서 도는 비결은 I/O 없는 순수 함수로 코어를 짜고, 플랫폼별 캡처 어댑터만 갈아끼운 것이다. 이건 어떤 JS 라이브러리에도 적용되는 이식성 설계 원칙이다.

⑦ AI 에이전트 스킬 설계 — LLM을 절제해서 쓰는 법

SKILL.md는 "결정론 코어 + LLM은 지각·판단만"이라는 사상의 실물이다. 대화형 리파인 테이블, "아트디렉터처럼 프리뷰를 심사하라"는 지침, 가독성 리포트 — AI를 어디에 쓰고 어디에 안 쓸지를 설계로 명시한 좋은 참고서다.

⑧ 테스트 전략 — 골든 파일 없이 속성으로 검증

test/e2e.js는 합성 손글씨(SVG stroke로 만든 가짜 필체)를 jpeg로 렌더해 전체 파이프라인을 통과시킨 뒤, 산출된 폰트를 opentype.js거꾸로 파싱해 메트릭·와인딩을 검증한다. "정답 이미지와 픽셀 비교"가 아니라 "결과물이 만족해야 할 속성"을 검사하는 속성 기반 검증의 좋은 예다.

7하드웨어 / 시스템 요구사항

Node 18 하나면 끝 — GPU도 서버도 없다
항목요구 / 비고
런타임Node.js 18 이상 (CLI·스킬). 브라우저 데모는 최신 브라우저
시스템 의존성없음 — FontForge·ImageMagick·potrace 바이너리 불필요
C 컴파일러불필요 — sharp는 프리빌트 바이너리, 벡터화는 순수 JS/WASM
GPU / 서버불필요 — 전부 CPU에서, 로컬에서 실행
이미지 상한CLI 최대 4200px, 브라우저 데모 최대 2800px로 리사이즈
브라우저 데모 요건WebAssembly + Canvas API + FontFace API 지원

요약하면, "평범한 노트북 + Node.js"가 요구사항의 전부다. 클라우드 계정도, 그래픽카드도, 무거운 런타임도 필요 없다. 이 가벼움이 "누구나 5분 안에 자기 손글씨 폰트를 만든다"는 이 프로젝트의 약속을 뒷받침한다.

현실적 주의
결과 품질은 "입력 사진"에 크게 좌우된다

도구가 아무리 좋아도, 흐릿하거나 기울어졌거나 그림자가 심한 사진은 세그먼트 단계에서 글자를 잘못 오려낸다. 균일한 조명, 정면 촬영, 진한 펜(옅은 볼펜보다 사인펜), 그리고 제공된 A4 템플릿 사용이 성공률을 크게 높인다. references/troubleshooting.md가 "글자가 붙어 나온다 / 조각이 흩어진다" 같은 증상별 처방을 담고 있다.

8직접 해볼 수 있는 실습 과제

난이도별 5개 — 첫 폰트 만들기부터 v2 기능 프로토타입까지
과제 1 · 난이도 ★☆☆☆☆

내 손글씨로 첫 폰트 만들기

종이에 알파벳 A~Z, a~z를 또박또박 쓰고 사진을 찍은 뒤, npx draw-your-font make photo.jpg --chars "ABC...xyz" --name "My Hand"를 실행하라. 나오는 TTF를 운영체제에 설치해 실제로 타이핑해 본다. 그다음 --smooth·--weight 옵션을 바꿔가며 프리뷰가 어떻게 달라지는지 비교하라.

과제 2 · 난이도 ★★☆☆☆

템플릿 → 채우기 → 라벨 JSON → 빌드, 각 단계 분해

draw-your-font template --charset spanish로 A4 연습지 PDF를 뽑아 인쇄·작성하고, segment로 글자를 오려낸 뒤 라벨 JSON을 직접 작성해 build까지 수동으로 이어붙여라. make가 자동으로 하던 일을 손으로 쪼개 보면 파이프라인 각 단계의 입출력이 명확히 보인다.

과제 3 · 난이도 ★★★☆☆

새 문자셋 추가 — 한글 자모 커버리지 확장

charsets.js에 한글 자모(ㄱㄴㄷ… ㅏㅑㅓ…)나 키릴 문자 같은 새 charset을 정의하고, metrics.js의 밴드 정의(BANDS)에 해당 문자 그룹의 수직 위치를 등록하라. 라틴 알파벳 밖으로 커버리지를 넓히는 과정에서 "글자 그룹별 메트릭"이라는 개념을 체득하게 된다.

과제 4 · 난이도 ★★★★☆

와인딩 교정을 꺼서 "구멍이 메워지는" 현상 재현

winding.jsfixWinding를 우회하도록 코드를 임시 수정하고 'o'·'b'·'g'·'a'를 빌드해, 구멍이 까맣게 차오르는 걸 직접 관찰하라. 그다음 다시 켜서 정상 복구를 확인한다. nonzero 와인딩 규칙이 "왜 반드시 필요한지"를 눈으로 각인시키는 실험이다. 여유가 되면 metrics.js의 밴드 수치를 바꿔 타이포 인상이 어떻게 변하는지도 실험해 보라.

과제 5 · 난이도 ★★★★★

v2 기능 프로토타입 또는 브라우저 데모 확장

README가 예고한 v2 방향(fonttools의 calt 기능을 이용한 커닝·리거처·글자 랜덤화 — 같은 글자가 나올 때마다 미세하게 다른 모양을 써서 더 "손글씨답게" 만들기)을 프로토타이핑하라. 또는 브라우저 데모(site/demo.src.js)에 굵기·매끄러움 실시간 슬라이더를 추가해 인터랙티브 UX를 개선해 본다.

9관련 기술 심화 학습 로드맵

6주 커리큘럼 — 이 저장소를 발판으로 이미지→폰트 전 영역 훑기
주차주제할 것
1주차고전 컴퓨터비전이미지 이진화·적응형 임계화·모폴로지·연결요소 라벨링 학습 → capture.js/blob-core.js 정독하며 "실제 사진에서 잉크만 뽑는 법" 체득
2주차벡터화 & 곡선potrace 알고리즘의 원리와 베지어 곡선 수학 기초 → trace.js가 비트맵을 어떻게 SVG path로 바꾸는지 추적
3주차타이포그래피 좌표계UPM·baseline·cap/x-height·사이드베어링·advance·와인딩 규칙 → metrics.js/winding.js 정독 + 밴드 수치 실험
4주차폰트 포맷SVG-font·TTF·OTF·WOFF·WOFF2 구조와 @font-faceassemble.js 추적 + opentype.js·fonttools로 폰트 역파싱 실습
5주차이식성 설계Node↔브라우저 순수 코어 공유 원칙 → esbuild 번들링 → site/demo.src.js가 코어를 어떻게 재사용하는지 분석
6주차AI 에이전트 스킬결정론 코어 + LLM은 지각/판단만 하는 분리 설계 → SKILL.md 패턴 학습 → 내 도구에 "AI가 심사·라벨하는" 스킬 레이어 붙여보기
학습 순서 팁

이 저장소는 "이미지 한 장을 구조화된 산출물로 바꾸는 파이프라인"의 종합 교재다. 손글씨 폰트라는 주제를 빼고 봐도, 전처리(이진화) → 분할(세그먼트) → 인식(라벨) → 변환(벡터화) → 조립(포맷)이라는 흐름은 문서 스캔·OCR·도면 디지털화 등 수많은 문제에 그대로 적용된다. 이 흐름을 한 번 손에 익히면 응용 범위가 매우 넓어진다.

10핵심 키워드 사전

이 문서에 나온 용어 빠른 정리
용어
적응형 임계화이미지 전체에 한 기준을 쓰지 않고, 위치별 로컬 배경 밝기에 맞춰 잉크/배경을 가르는 이진화. 그림자·조명 얼룩에 강함
연결요소 라벨링서로 붙어 있는 픽셀 덩어리를 하나의 객체(글자)로 묶는 알고리즘. flood fill로 순회
flood fill한 픽셀에서 시작해 인접한 같은 색 픽셀로 번져 나가며 영역을 채우는 순회 기법(페인트통 도구의 원리)
모폴로지 연산grow(팽창)/shrink(침식)로 획을 잇거나 노이즈를 지우는 형태 기반 이미지 연산
벡터화 / potrace픽셀 비트맵의 윤곽을 매끄러운 수학 곡선(베지어)으로 따내는 작업과 그 대표 엔진
베지어 곡선제어점으로 정의되는 매끄러운 곡선. 폰트·벡터 그래픽스의 기본 요소
UPM (units per em)폰트 내부 좌표계의 한 칸 크기(보통 1000 또는 2048). 모든 글자가 이 좌표계를 공유
cap height / x-height대문자 높이 / 소문자(x) 높이. 폰트의 시각적 인상을 좌우하는 핵심 메트릭
ascender / descender기준선 위로 올라가는 부분(h·b) / 아래로 내려가는 부분(g·y)
사이드베어링 / advance width글자 좌우 여백 / 다음 글자까지 커서가 나아가는 폭(자간의 기초)
nonzero vs even-odd다각형 내부를 판정하는 두 규칙. TrueType은 nonzero라, 구멍은 바깥선과 반대 방향이어야 뚫린다
signed area (신발끈 공식)다각형 꼭짓점 좌표로 넓이와 회전 방향(부호)을 동시에 구하는 공식
point-in-polygon한 점이 다각형 안에 있는지 판정(ray casting). 구멍의 중첩 깊이 계산에 사용
SVG-font글리프를 SVG path로 기술하는 폰트 XML 형식. svg2ttf로 TTF로 변환
TTF / WOFF / WOFF2설치용 폰트(TTF)와 웹용 압축 폰트(WOFF·WOFF2). WOFF2가 가장 작음
EXIF orientation사진 파일에 저장된 회전 정보. 무시하면 세로/가로가 뒤집혀 처리됨
sharp / libvipsNode의 고속 이미지 처리 라이브러리와 그 내부 저메모리 엔진
WASM브라우저·Node에서 네이티브급 속도로 도는 이식 가능한 바이너리(potrace·wawoff2)
컨택트 시트오려낸 글자 조각들을 한 장에 모은 이미지. AI 비전이 이걸 보고 라벨을 붙임
Claude Code 스킬AI 에이전트가 대화로 도구를 지휘하게 하는 지침 묶음(SKILL.md). 여기선 심사·라벨 담당

11참고 링크

원문으로 더 파고들기