Pretext: 멀티라인 텍스트 측정과 레이아웃을 위한 TypeScript 라이브러리
3 days ago
4
-
Pretext는 DOM 접근 없이 멀티라인 텍스트의 높이와 줄 배치를 계산하는 순수 JavaScript/TypeScript 라이브러리로, 브라우저와 서버 환경 모두 지원
-
getBoundingClientRect 같은 DOM 측정 API를 사용하지 않아 레이아웃 리플로우 비용을 제거하고, 폰트 엔진 기반 자체 측정 로직으로 정확도를 확보
-
prepare() / layout() API를 통해 텍스트를 전처리하고, 캐시된 폭 데이터를 이용해 순수 산술 연산으로 빠른 높이 계산 수행
-
이모지, 혼합 방향 텍스트(bidi), 다양한 언어를 지원하며, Canvas·SVG·WebGL·서버 렌더링에서도 동일한 결과 제공
-
가상화 스크롤, 텍스트 오버플로 검증, 플로팅 텍스트 배치 등 정밀한 UI 레이아웃 구현에 활용 가능한 고성능 텍스트 엔진임
개요
-
Pretext는 멀티라인 텍스트 측정과 레이아웃을 위한 순수 JavaScript/TypeScript 라이브러리로, DOM, Canvas, SVG, 그리고 서버 사이드 렌더링까지 지원
-
DOM 측정 API(getBoundingClientRect, offsetHeight 등)를 사용하지 않아 레이아웃 리플로우 비용을 제거함
- 브라우저의 폰트 엔진을 기준으로 한 자체 측정 로직을 통해 정확하고 빠른 성능을 제공
-
모든 언어, 이모지, 혼합 방향 텍스트(bidi) 를 지원하며, 브라우저별 차이도 처리
설치 및 데모
주요 기능
- Pretext는 두 가지 주요 사용 방식을 제공
-
1. DOM 접근 없이 문단 높이 측정
-
prepare()는 텍스트를 전처리하고, 공백 정규화·세그먼트 분리·glue 규칙 적용·canvas 기반 측정을 수행해 불투명 핸들(opaque handle) 을 반환
-
layout()은 캐시된 폭 데이터를 이용해 순수 산술 연산으로 높이와 줄 수 계산
- 동일한 텍스트와 설정에서는 prepare()를 반복 호출하지 않고, 리사이즈 시에는 layout()만 다시 실행
-
{ whiteSpace: 'pre-wrap' } 옵션으로 공백, 탭(\t), 줄바꿈(\n)을 그대로 유지
- 벤치마크 결과: prepare() 약 19ms (500개 텍스트 기준), layout() 약 0.09ms
- 반환된 높이 값은 다음과 같은 UI 기능에 활용 가능
-
가상화 및 오클루전 처리에서 정확한 높이 계산
-
JS 기반 레이아웃 시스템(예: masonry, flexbox 유사 구조)
-
AI 기반 텍스트 오버플로 검증
-
텍스트 로드 시 스크롤 위치 유지
-
2. 수동 문단 레이아웃 구성
-
prepareWithSegments()로 세그먼트 단위 데이터 생성
-
layoutWithLines()는 고정 폭에서 각 줄의 텍스트와 폭 정보를 반환
-
walkLineRanges()는 텍스트 문자열을 만들지 않고 각 줄의 폭과 커서 범위를 순회
- 예: 여러 폭을 테스트해 적절한 줄 수와 높이를 찾는 이진 탐색형 레이아웃 조정 가능
-
layoutNextLine()은 줄마다 폭이 달라지는 경우 한 줄씩 순차적으로 레이아웃
- 예: 이미지 주위로 텍스트를 흐르게 하는 플로팅 텍스트 배치
- 이 방식은 Canvas, SVG, WebGL, 서버 사이드 렌더링에도 동일하게 적용 가능
API 요약
-
기본 측정용 API
-
prepare(text, font, options?): 텍스트 분석 및 측정, layout()에 전달할 핸들 반환
-
layout(prepared, maxWidth, lineHeight): 주어진 폭과 줄 높이에 따른 텍스트 높이와 줄 수 계산
-
수동 레이아웃용 API
-
prepareWithSegments(text, font, options?): 세그먼트 단위 데이터 반환
-
layoutWithLines(prepared, maxWidth, lineHeight): 각 줄의 텍스트, 폭, 커서 정보 포함
-
walkLineRanges(prepared, maxWidth, onLine): 각 줄의 폭과 커서 범위를 콜백으로 전달
-
layoutNextLine(prepared, start, maxWidth): 줄 단위 반복자 형태로 레이아웃 수행
-
LayoutLine, LayoutLineRange, LayoutCursor 타입 정의 포함
-
기타 유틸리티
-
clearCache(): 내부 캐시 초기화
-
setLocale(locale?): 로케일 설정 및 캐시 초기화 (기존 상태에는 영향 없음)
제약 및 주의사항
- Pretext는 완전한 폰트 렌더링 엔진은 아님
- 기본 대상 CSS 속성
-
white-space: normal
-
word-break: normal
-
overflow-wrap: break-word
-
line-break: auto
-
{ whiteSpace: 'pre-wrap' } 사용 시 공백, 탭, 줄바꿈 유지하며 tab-size: 8 적용
- macOS에서 system-ui 폰트는 layout() 정확도에 부적합하므로 명시적 폰트명 사용 권장
-
overflow-wrap: break-word로 인해 매우 좁은 폭에서는 단어 내부에서도 줄바꿈 가능, 단 문자 단위(grapheme) 기준으로만 분리
개발 관련
- 개발 환경 및 명령은 DEVELOPMENT.md 참고
기여 및 배경
-
Sebastian Markbage의 text-layout 프로젝트에서 아이디어를 이어받음
-
canvas measureText 기반 셰이핑, pdf.js의 bidi 처리, 스트리밍 라인 브레이킹 설계를 계승해 발전시킨 구조
-
Homepage
-
개발자
- Pretext: 멀티라인 텍스트 측정과 레이아웃을 위한 TypeScript 라이브러리