# ADR-011: 기본 제공 자소판은 획으로 직접 그린 SVG

## Status
Accepted

## Date
2026-10-09

## Context
기본 제공 그림 자소 글꼴 5종(`sprite-system`·`sprite-example`과 파생 `pixel`·`dojang`·`chalk`)의 자소판은 PNG였고, 그 그림은 Apple 기기 글꼴(Apple SD Gothic Neo, AppleGothic)의 글자 모양에서 잘라 낸 것이었다. 기기 글꼴의 사용권은 화면 표시를 허락할 뿐 글자 모양을 글꼴 대용으로 재배포할 권리를 주지 않으므로, 공개 배포 전에 바꿔야 했다(TODO P0, THIRD_PARTY_NOTICES).

바꾸는 길은 둘이었다.

- **재배포가 허용된 글꼴(SIL OFL)에서 다시 잘라 내기.** 기존 추출기(`scripts/extract_sprite_from_syllables.py`)를 Noto Sans KR로 돌리면 된다. 그러나 결과물은 OFL 글꼴의 수정본이라 패키지 라이선스가 MIT와 OFL로 갈리고, 래스터라 큰 글자에서 계단이 진다. 실측해 보니 Noto는 줄 상자 안에서 글자가 약 0.1em 내려가 있어(세로 0.962배, −0.106em) 받침 행이 잘렸고, 기존 배치를 그대로 쓰려면 좌표 정규화가 필요했다.
- **직접 그리기.** 사람이나 AI 에이전트가 자모를 그려 자소판을 만드는 것은 그림 자소 글꼴의 원래 약속이다(소개문 "이미지 자소 기반 방식"). SVG로 그리면 크기와 상관없이 선명하고, 재료(굵기·색·질감)가 몇 줄의 스타일이다.

자소판 칸은 음절 1em 상자를 그대로 줄인 것이라 자모가 제자리에 미리 놓이고, `sprite-system.css`의 자리 배치는 그 위치를 전제로 보정돼 있다. 새 그림이 같은 자리에 놓이면 배치를 그대로 쓸 수 있다.

## Decision

### 1. 자리 상자를 계약으로 둔다 — `spec/sprite-layout.json`
칸마다 자모 잉크가 차지할 상자 `[x0, y0, x1, y1]`(칸 한 변 100)를 둔다. 두 짝 자음·겹받침·합자 모음은 짝별 상자(`parts`)도 둔다. 수치는 이전 자소판의 칸 잉크 상자를 잰 값이다(글자 모양은 담지 않는다 — sebul·gothic 배치가 기기 글꼴 렌더를 잰 수치인 것과 같은 성격). 배치는 두 벌이다: `system`(6행, sprite-system과 파생 글꼴)과 `starter`(2행 낱자, sprite-example). npm 패키지에 포함한다 — 외부 사용자와 AI가 같은 상자 안에 그리면 sprite-system의 보정된 배치를 그대로 물려받는다.

### 2. 획 정의 하나에서 자소판 5종을 그린다 — `scripts/build_jamo_svg.js`
- 자모는 획 중심선으로 정의한다. 좌표는 자리 상자를 획 두께 절반만큼 줄인 상자의 0–1 단위라 획 바깥선이 상자에 닿는다. 형식은 SVG 경로 문법(`"M0 0 H1 V1"`)이고, 끝 늘이기(`s`·`e`, 획 두께 배수)로 접합부를 상대 획 안에 묻는다. 문맥(세로 모음 옆 초성·가로 모음 위 초성·받침·낱자)별 모양을 둘 수 있다 — 세로 모음 옆 ㄱ·ㅋ의 휜 다리, 윗부분이 좁은 ㄷ·ㄹ·ㅌ·ㅍ.
- 재료(STYLES)는 굵기·색·끝 모양과 질감이다: `sprite-system` 7.2(칸 100 기준) 납작한 끝, `sprite-example` 3.8 둥근 끝, `dojang`은 인주 필터(번짐·종이결·누름 얼룩), `chalk`는 분필 필터(흔들린 가장자리·결·가루 빠짐), `pixel`은 칸 20×20 격자에 중심선을 1도트로 찍고(브레젠험 선, ㄴ자 모서리 도트 제거) 짝 상자 안쪽으로 한 도트 겹쳐 찍은 굵은 도트다. 필터의 잡음 주기는 칸 단위라 질감이 글자 크기와 함께 늘어난다.
- 출력 SVG의 칸은 `<g id="r<행>-<자모>" transform="translate(x y)">`이고 안의 좌표는 칸 기준 0–100이다. 사람과 AI가 그대로 읽고 고칠 수 있다.
- 칸 가장자리 2단위(도트는 한 도트)에는 잉크를 두지 않는다. 브라우저는 늘린 자소판을 다시 래스터화하며 이웃 칸을 한두 픽셀 섞어 읽어(아틀라스 번짐), 칸 경계에 닿은 잉크가 옆 글자 밑에 가는 줄로 비쳤다.
- `npm test`가 `--check`로 자소판이 획 정의와 같은지 검사한다. 파생 글꼴 생성기(`build_derived_fonts.js`)는 자소판 주소를 `./<id>.svg`로 바꾸고, 파생 자소판이 기반과 같은 배치로 그려졌는지 이 생성기에 묻는다. PNG를 다시 칠하던 `build_material_sheets.py`는 지운다.

### 3. 런타임 계약은 그대로
`--fy-sprite-url`은 원래 `<url>`이라 SVG를 그대로 받는다. 코어 규칙·린트·사이드카는 바뀌지 않는다. 자소판 크기 비율만 칸 격자와 맞으면 되고, SVG의 `width`·`height`는 이전 PNG와 같은 값(칸 128px, 입문용 64px)으로 둬 글꼴 작업실의 칸 크기 판정도 그대로다.

### 4. 글꼴 작업실은 SVG를 PNG로 고친다
재료 탭은 SVG 자소판을 캔버스에 올려 그대로 보여 준다. 픽셀로 처음 고치거나 PNG를 가져오면 글꼴의 `--fy-sprite-url`을 옆의 `<이름>.png`로 바꾸고 내보내기 이름도 PNG로 한다 — SVG 파일 자체는 건드리지 않는다. 획을 고치려면 SVG를 직접 편집한다.

### 5. 글꼴에서 잘라 내는 길은 재배포 허용 글꼴만
추출기의 기본 기준 글꼴을 Noto Sans KR(OFL 1.1)로 바꾸고, 측정 하네스의 기준 웹폰트 캐시에 family별 원본(`WEBFONT_SOURCES`)과 OTF 형식을 더한다. 잘라 낸 자소판은 원본 글꼴의 라이선스를 따른다.

## Alternatives Considered
### OFL 글꼴(Noto Sans KR)에서 다시 잘라 낸 PNG
- 장점: 기존 파이프라인 그대로, 전문 글꼴의 획 품질.
- 단점: 자소판이 OFL 수정본이 되어 패키지 라이선스가 갈린다. 래스터라 큰 글자에서 계단이 진다. 세로 메트릭이 달라 좌표 정규화와 재교정이 필요했다(ㅆ·ㅉ는 모음과 붙어 잘라 내지도 못했다). 무엇보다 "직접 그린다"는 그림 자소의 약속을 보여 주지 못한다.

### OFL 글꼴 외곽선을 SVG로 뽑기
- 장점: 벡터이면서 글꼴 품질.
- 단점: 여전히 OFL 수정본이고, 외곽선은 굵기·재료를 바꾸기 어렵다. 사람·AI가 고치기에도 중심선보다 훨씬 복잡하다.

### SVG 자소판을 사람이 손으로 하나씩
- 장점: 생성기가 없다.
- 단점: 93칸 × 5재료를 손으로 맞추면 배치·굵기가 어긋난다. 획 정의 하나에서 재료를 바꿔 그리는 편이 일관되고, 한 획을 고치면 다섯 자소판이 함께 바뀐다.

## Consequences
### Positive
- 기본 제공 자소판 전체가 이 저장소의 저작물이라 코드와 같은 MIT다. 외부 글꼴 고지가 필요 없다.
- 어느 크기로 늘려도 선명하다. 받침처럼 눌린 칸도 획 굵기가 일정하다.
- 자소판이 작다: 원본 15–31KB, gzip 약 4KB(이전 PNG 83–117KB).
- 사람과 AI가 같은 형식으로 새 그림 자소 글꼴을 그릴 수 있다 — 자리 상자 안에 그리면 배치는 이미 맞는다.
- 겹침 감사(초성 계열 약 1,050자): sprite-system·pixel·dojang·chalk 모두 예외 0. sprite-example(배치 기본값 그대로인 입문용)의 예외 12건은 모두 이전 상한 아래로 내려왔다.

### Negative
- 획 굵기에 대비가 없는 기하학적 고딕이라, 이전(Apple SD Gothic Neo 잘라 낸 그림)보다 글꼴다운 붓맛은 덜하다.
- SVG 필터(인주·분필)는 큰 글자에서 래스터화 비용이 PNG보다 크다. 같은 크기는 브라우저가 한 번만 그린다.
- 글꼴 작업실의 픽셀 편집은 SVG를 PNG로 바꿔 저장한다(벡터 편집기는 아니다).

### Risks
- 자리 상자가 이전 그림의 잉크 상자에서 왔으므로, 획 정의가 상자 안의 내부 비례(ㄹ 윗부분 폭, ㅖ 곁가지 길이 등)를 크게 바꾸면 이웃 자모와 닿는다 — 겹침 감사(family 표본)가 잡는다. 실제로 ㄹ 윗부분을 상자 끝까지 채운 첫 그림은 렚·렑(16.3%)에서 걸렸다.
- 도트는 칸마다 따로 격자에 붙이므로 반올림 보정(`pixel.css`의 받침·가로 모음 위 초성·통짜 합자 모음 이동)이 획 정의 변경에 따라 달라질 수 있다.

## Related Documents
- ADR: [ADR-008 글꼴 계약 v2](./ADR-008-font-contract-v2.md), [ADR-010 파생 글꼴](./ADR-010-derived-fonts-and-script-loader.md)
- Architecture: [그림 자소 글꼴](../ARCHITECTURE/image-sprite-fonts.md), [글꼴 작업실](../ARCHITECTURE/font-studio.md)
- 라이선스: [Third-party notices](../../THIRD_PARTY_NOTICES.md)

## Change Log
- 2026-10-09: 기본 제공 자소판 5종을 획 정의에서 그린 SVG로 교체하며 Accepted로 기록
