비트맵 폰트 만들기

격자형 폰트 시트와 문자 순서로 PNG·BMFont·JSON을 만드세요.

로컬에서 픽셀 글리프를 그리거나 PNG 시트·BDF·편집 프로젝트를 가져올 수 있습니다. 도구는 PNG 아틀라스 한 장과 같은 수치의 BMFont 텍스트·XML·버전 3 바이너리를 내보냅니다. 편집 프로젝트에는 v2 원본과 한도 안에서 TrueType 픽셀 윤곽선 폰트도 들어갑니다. 입력한 문장의 누락 글자 수와 커닝 미리보기를 볼 수 있으며 파일은 업로드하지 않습니다. CC0 BDF 두 종의 출력은 독립적으로 재열었지만 새 BDF 경로의 엔진 적재는 별도 검증 대상입니다.

이미지을(를) 여기에 놓으세요여러 개를 한 번에 처리할 수 있습니다
업로드 없음 · 이 기기에서 처리

.fnt 파일이 말하는 것, 한 줄씩

info는 글꼴 이름과 크기, 여백과 간격을 적습니다. common에는 lineHeight(텍스트 한 줄에서 다음 줄까지 픽셀), base(줄 맨 위에서 베이스라인까지 픽셀), scaleW·scaleH(텍스처 크기), pages가 있습니다. page id=0 file="font.png"는 .fnt 기준 상대 경로로 텍스처를 가리킵니다. char 줄마다 id(10진수 유니코드 코드 포인트), x y width height(텍스처 안 글리프 사각형), xoffset yoffset(펜 위치와 줄 맨 위 기준으로 그 사각형을 그릴 자리), xadvance(그 뒤 펜 이동 거리)가 있습니다. kerning first second amount 줄은 특정 글자 쌍을 조정하는데, 편집 프로젝트는 글자 쌍 커닝을 저장하지만 이미지 시트에는 가져올 커닝 정보가 없습니다.

엔진은 문자열을 그릴 때 펜을 x = 0에서 시작해 글자마다 사각형을 (펜 + xoffset, 줄 맨 위 + yoffset)에 복사하고 펜에 xadvance를 더하며, 다음 줄은 lineHeight만큼 아래에서 시작합니다. 고정 격자 모드에서는 모든 전진 폭이 칸 너비라 고정폭 픽셀 폰트에 맞습니다. 측정 모드는 칸마다 불투명 픽셀(알파 8 초과)만 남기고 오프셋으로 원래 자리에 되돌리며, 잉크 오른쪽 끝에 글리프 간격을 더한 만큼 전진합니다. 공백처럼 빈 칸도 전진합니다.

문자 집합이 아틀라스 크기를 정합니다. ASCII는 95자(U+0020~U+007E), Latin-1은 191자이고, 완성형 한글만 11,172음절, 주요 한중일 한자 블록은 20,992 코드 포인트이므로 한국어·일본어 프리셋은 붙여 넣은 텍스트에 실제로 나오는 글자만 가져옵니다. 부호 있는 거리장(SDF)은 텍셀마다 덮임 정도 대신 글리프 가장자리까지의 거리를 저장해, 셰이더가 다른 크기에서도 날카로운 경계를 자를 수 있게 합니다. Nerulio는 128을 가장자리로, spread 픽셀의 거리를 바이트 범위에 담고, 글리프마다 4배 해상도에서 정확한 거리를 계산하며, MSDF가 아닌 단일 채널 SDF를 만듭니다.

lineHeight
텍스트 한 줄에서 다음 줄까지의 픽셀.
base
줄 맨 위에서 베이스라인까지의 픽셀.
xoffset / yoffset
펜과 줄 맨 위를 기준으로 글리프 사각형을 그리는 위치.
xadvance
글리프를 그린 뒤 펜이 이동하는 거리.
SDF spread
0~255 범위가 담는 거리(픽셀). 128이 글리프 가장자리.

예시: 같은 글리프 세 개를 격자·측정 모드로

A, i, 공백을 위한 8 × 8 칸이 있는 24 × 8 시트, 베이스라인 7. 도구가 쓰는 줄입니다.

common    lineHeight=8 base=7 scaleW=24 scaleH=8 pages=1
격자      char id=65  x=0  y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8
          char id=105 x=8  y=0 width=8 height=8 xoffset=0 yoffset=0 xadvance=8
측정      char id=65  x=1  y=1 width=5 height=6 xoffset=1 yoffset=1 xadvance=7   (1 + 5 + 간격 1)
          char id=105 x=11 y=1 width=1 height=6 xoffset=3 yoffset=1 xadvance=5   (3 + 1 + 1)
          char id=32  x=16 y=0 width=0 height=0 xoffset=0 yoffset=0 xadvance=3   (빈 칸: round(8 ÷ 3))
"iA i" 측정   i는 0 + 3 = 3 → 펜 5;  A는 5 + 1 = 6 → 펜 12;  공백 → 펜 15;  i는 18 → 너비 20px
"iA i" 격자   글리프 4개 × 8 = 32px

측정 폰트는 i를 8px이 아니라 5px 간격으로 놓아 비례 텍스트가 자연스럽게 보입니다. font.json에도 같은 값이 glyphs[].xAdvance, xOffset, yOffset로 들어 있습니다.

엔진에서 폰트 불러오기

  1. font.fnt와 font.png를 함께 두세요. page 줄이 PNG를 상대 파일 이름으로 가리키므로 이름을 바꾸려면 둘 다 바꿔야 합니다.
  2. Godot 4: 두 파일을 프로젝트에 복사하면 Godot가 .fnt를 비트맵 폰트로 가져옵니다. Label 등 Control의 폰트 테마 오버라이드에 지정하세요. 비트맵 폰트는 설계 크기가 고정이므로 픽셀 폰트는 그 크기나 정수배로 그리세요.
  3. PixiJS 8: await Assets.load('font.fnt') 뒤 new BitmapText({ text, style: { fontFamily: 'Nerulio Grid' } })를 만듭니다. family는 info 줄의 face입니다(Nerulio Grid, Nerulio Measured, 또는 Nerulio와 폰트 파일 이름).
  4. Phaser: this.load.bitmapFont(key, 'font.png', 'font.xml')를 사용하세요. ZIP에 PNG와 XML 설명자가 함께 들어 있습니다. 사용 중인 Phaser 버전에서 실제 표시를 확인하세요.

결과 확인

  • 텍스트 편집기로 font.fnt를 엽니다. chars count가 char 줄 수와 같고, 모든 사각형이 scaleW × scaleH 안에 있어야 합니다.
  • 시트 아래 예시 줄은 폰트 자신의 수치로 그립니다. 여기서 겹치거나 벌어지는 글자는 엔진에서도 그렇게 됩니다.
  • 배포 전에 현지화 파일로 이 폰트를 누락 글리프 검사에 돌려 보세요.

문제 해결

증상유력한 원인확인 방법해결
엔진이 폰트를 불러오는데 아무것도 안 보임font.png 이름을 바꿨거나 .fnt와 다른 곳으로 옮김page id=0 file= 줄과 실제 파일 이름page 줄에 적힌 이름으로 PNG를 .fnt 옆에 두기
Phaser가 폰트를 해석하지 못함Phaser load.bitmapFont는 BMFont의 XML 형식을 요구함로더가 데이터를 해석할 때의 콘솔 오류포함된 font.xml을 font.png 옆에 놓고 Phaser 콘솔과 파일 경로를 확인
측정 모드에서 글자가 붙거나 너무 벌어짐글리프 간격 값, 또는 알파 8을 넘는 흐린 픽셀이 잉크 상자를 넓힘.fnt에서 좁은 글리프와 넓은 글리프의 xadvance 비교글리프 간격을 바꾸거나 시트의 흐린 픽셀을 지우기
폰트 파일 모드: info size가 고른 크기보다 큼크기에 입력한 폰트 크기가 아니라 칸 높이(ascent + descent + 여백)를 씀info size와 폰트 크기 칸 비교엔진이 size를 쓰는 곳에서는 렌더링한 크기를 직접 지정
폰트 파일 모드: 일부 글자가 다른 서체처럼 보임TTF에 없는 글자를 브라우저 대체 폰트가 그려 시트에 구워 넣음글리프 시트에서 모양이 다른 글자 찾기그 글자를 빼거나, 그 글자가 있는 폰트 파일 고르기
폰트 파일 모드: 픽셀 폰트가 흐리게 나옴캔버스 텍스트는 안티앨리어싱되어 가장자리에 반투명 알파가 생김시트를 확대하면 가장자리에 회색 픽셀픽셀 폰트는 시트로 그려 격자·측정 모드 사용
격자 모드에서 글자 순서가 격자에 맞지 않는다고 나옴칸보다 글자가 많거나, 같은 글자가 반복되거나, 순서가 비어 있음시트의 열 × 행과 글자 수 비교중복을 빼거나 더 큰 시트 사용. 가장자리의 칸보다 좁은 띠는 무시됨

다른 방법

방법이럴 때 더 낫습니다
Godot 자체 이미지 폰트 가져오기(가져오기 유형 Font Data (Image Font))Godot에서만 쓰고 시트 순서가 단순할 때. 추가 파일이 없고, 가져오기 독에서 문자 범위·여백·커닝 쌍도 지정할 수 있습니다.
AngelCode BMFont 등 BMFont 호환 생성기검증된 여러 텍스처 페이지, 효과 또는 고급 폰트 기능이 필요할 때. 이 편집기는 현재 아틀라스 한 장을 씁니다.
엔진에서 동적 폰트(TTF 자체) 사용글자 크기가 크게 바뀌거나 수천 개 글리프가 필요한 언어일 때. Godot 문서는 MSDF 렌더링을 비트맵 폰트가 아닌 동적 폰트에 대해 설명합니다.

이 방법의 한계

  • 아틀라스 1장만 출력하며 로컬 TTF/OTF 굽기와 BDF/프로젝트 편집은 현재 최대 1,024자입니다. 여러 페이지 CJK 출력·OTF 다운로드는 검증되지 않았습니다. SDF는 베타입니다. 문자 수가 맞아도 조합 한글의 가독성은 보장되지 않습니다.
  • 편집 TTF는 픽셀 사각형 윤곽선을 사용합니다. CC0 BDF 두 종은 fontTools로 재열었지만 FreeType 기본 힌팅에서 i·j의 분리된 점이 움직였습니다. Unity TextMeshPro 적재는 미검증입니다.
  • 기존 로컬 폰트 굽기는 브라우저 대체 글리프와 안티앨리어싱이 섞일 수 있습니다. 대상 엔진에서 다운로드한 아틀라스를 확인하세요.

버전과 출처

docs/UI-LAB.md를 위해 Chromium에서 측정했습니다. 고정 격자 폰트는 16 × 8 font.png에서 あ를 char id=12354 x=8 y=0 width=8 height=8로 쓰고, 테스트 안의 독립 파서가 .fnt 헤더와 모든 글리프 레코드를 JSON과 같게 읽었습니다. 측정 모드는 딱 맞는 사각형, 세 가지 이상의 전진 폭, 전진하는 빈 칸을 만들었고, TTF에서 32px ASCII-95 아틀라스는 28ms(350 × 380 시트), SDF는 1174ms에 만들어졌습니다. 위의 폰트 파일 모드 문제는 이번 버전에서 아직 고치지 못한 알려진 문제입니다. BMFont 필드는 AngelCode 문서를, 엔진 불러오기는 Godot 4.7·PixiJS 8·Phaser API 문서를 따릅니다.

참고한 공식 문서

예제

원본 도형 샘플 · 96 × 64
원본 도형 샘플 · 96 × 64
도구로 처리한 샘플 · 96 × 64
도구로 처리한 샘플 · 96 × 64

이 도구로 만든 예제입니다. ZIP 도구는 미리보기를 표시하며 전체 파일은 내려받은 압축 파일에서 확인하세요.

비트맵 폰트 만들기

격자형 폰트 시트와 문자 순서로 PNG·BMFont·JSON을 만드세요.

사용 방법

  1. 이미지 넣기
  2. 필요한 설정을 조정하고 결과 확인
  3. 다운로드로 새 파일 저장

지원 형식

PNG / JPG / WebP / AVIF / HEIC → PNG + FNT + JSON (ZIP) — 입력 디코딩은 브라우저 지원과 추가 엔진 사용 여부에 따라 다릅니다.

이 도구로 할 수 있는 일

격자형 폰트 시트와 문자 순서로 PNG·BMFont·JSON을 만드세요.

처리 방식과 검증 수준

advanced · fixed grid BMFont. 품질 검증을 진행 중입니다. Pro·Flagship 수준은 아직 입증되지 않았습니다.

저장 전에 확인하세요

고정 폭 격자 전용입니다. 커닝·가변 폭·Godot 리소스 자동 생성은 지원하지 않습니다.

자주 묻는 질문

이 도구의 한계는 무엇인가요?

고정 폭 격자 전용입니다. 커닝·가변 폭·Godot 리소스 자동 생성은 지원하지 않습니다.

파일이 서버에 업로드되나요?

이 도구에서 연 파일은 서버에 업로드하지 않고 사용자 기기에서 처리합니다. 커뮤니티 글에 직접 첨부하는 이미지는 별도로 업로드됩니다. 일부 엔진과 모델은 외부에서 내려받으므로 IP 주소 등 연결 정보가 해당 서비스에 전달됩니다.

작업이 자동 저장되나요?

아니요. 이미지와 편집 상태는 이 탭에 있고 미디어 결과는 기기 내 임시 저장소를 사용할 수 있습니다. 언어를 바꿔도 작업은 유지되지만 새로고침, 탭 닫기, 다른 페이지로 이동하면 사라질 수 있습니다.