Pretext 데모 로딩 중...

위 화면에서 공이 떠다니고 있다. 텍스트가 공 주위를 실시간으로 감싸며 흐른다. 공을 마우스로 잡아서 움직여보자. 텍스트가 즉시 재배치되는 게 보일 것이다.

이건 GIF가 아니다. 지금 이 순간, 브라우저 안에서 실시간으로 계산되고 있다.

이걸 만든 건 15킬로바이트짜리 라이브러리 하나다. 이름은 Pretext. 그리고 이 라이브러리가 해결한 문제는, 웹이 태어난 이래 30년 동안 안고 살아온 것이다.


웹에서 텍스트의 높이를 아는 건 왜 어려운가

이 질문이 이상하게 들릴 수 있다. 화면에 글자가 보이는데, 높이를 모른다니?

설명하자면 이렇다. 브라우저가 텍스트를 화면에 보여주는 과정은 우리가 생각하는 것보다 훨씬 복잡하다.

  1. 폰트 파일을 다운로드한다
  2. 텍스트를 글리프(도형)로 변환한다
  3. 각 글리프의 너비를 측정한다
  4. 줄바꿈 위치를 결정한다
  5. 각 줄을 수직으로 배치한다

모든 단계가 이전 단계에 의존한다. 3번의 너비를 알아야 4번의 줄바꿈을 결정할 수 있고, 줄바꿈이 결정되어야 전체 높이를 알 수 있다. 이 전체 과정을 "레이아웃"이라고 부른다.

여기까지는 괜찮다. 문제는 이 레이아웃 과정이 전부 브라우저 내부에서 일어난다는 것이다. 그리고 브라우저는 이 정보를 쉽게 내주지 않는다.

리플로우라는 비용

개발자가 "이 텍스트 블록의 높이가 몇 픽셀이야?"라고 물으면, 브라우저는 그 텍스트만 계산하는 게 아니라 화면 전체의 레이아웃을 처음부터 다시 계산한다. 이걸 "리플로우(reflow)"라고 부른다.

왜 전체를 다시 계산하냐? 웹 페이지의 요소들은 서로 영향을 주기 때문이다. 텍스트 블록의 높이가 바뀌면 아래에 있는 모든 요소의 위치가 바뀔 수 있다. 그래서 브라우저는 안전하게, 처음부터 전부 다시 계산한다.

블로그 글 하나를 읽을 때는 이게 전혀 문제가 안 된다. 페이지가 로드될 때 한 번 계산하면 끝이니까. 우리 눈이 본문 첫 줄에 도달하기 전에 모든 게 끝난다.

하지만 웹은 더 이상 글을 읽기만 하는 곳이 아니다.

500번의 리플로우

카카오톡이나 슬랙 같은 메시지 앱을 생각해보자. 채팅방에 메시지가 수천 개 있다. 스크롤을 빠르게 올리면 화면 밖의 메시지들이 새로 그려져야 한다. 이때 각 말풍선의 정확한 높이를 알아야 스크롤 위치를 계산할 수 있다.

메시지 500개의 높이를 알아야 한다면? 리플로우 500번. 한 번에 15~30밀리초. 합치면 수백 밀리초. 화면이 버벅인다.

매거진 스타일 레이아웃은 어떤가. 텍스트가 이미지를 감싸며 흘러야 한다. 이미지의 위치가 바뀔 때마다 텍스트의 줄바꿈이 전부 바뀐다. 매 프레임마다 리플로우를 일으켜야 한다면, 60fps는 꿈도 꾸지 못한다.

대시보드에서 패널 크기를 드래그로 조절할 때도 마찬가지다. 패널 안의 텍스트가 실시간으로 재배치되어야 하는데, 매 픽셀 이동마다 리플로우가 발생한다.

Chrome DevTools는 이걸 빨간 막대로 경고한다. Lighthouse는 점수를 깎는다. 하지만 개발자에게 대안이 없다. CSS는 텍스트를 실제로 화면에 그리지 않고 높이를 알려주는 기능을 제공하지 않는다.

정보는 DOM 뒤에 잠겨 있고, DOM은 모든 답변에 대가를 요구한다.

30년째.


CSS Shapes의 시도와 한계

사실 이 문제를 해결하려는 시도가 없었던 건 아니다.

2014년에 CSS Shapes라는 스펙이 확정됐다. 텍스트가 특정 도형 주변으로 감싸며 흐르게 해주는 기능이다. 원, 타원, 다각형, 심지어 이미지의 투명도까지 도형으로 쓸 수 있다.

종이 위에서는 완벽한 해답처럼 보였다. 실제로는 제약이 너무 많았다.

  • float 요소에만 작동한다. float은 현대 웹 레이아웃에서 거의 쓰이지 않는다
  • 텍스트가 도형의 한쪽 면만 감쌀 수 있다. 양쪽으로 동시에 흐르는 건 불가능하다
  • 도형을 CSS에 정적으로 정의해야 한다. 애니메이션이나 드래그로 도형을 움직이면? 리플로우가 발생한다
  • 결과 줄의 위치를 알 수 없다. 각 줄이 어디서 시작하고 끝나는지, 몇 줄이 생성됐는지, 전체 높이가 얼마인지. 이런 정보에 접근할 방법이 없다

인쇄 매거진에서 당연하게 볼 수 있는 것들. 텍스트가 사진을 감싸고, 인용문이 본문 사이에 떠 있고, 여러 컬럼으로 자연스럽게 이어지는 레이아웃. 이런 것들이 웹에서는 여전히 불가능하거나, 가능하더라도 성능 비용이 너무 높아서 실용적이지 않았다.

12년이 지난 지금도 이 제약은 그대로다.


Pretext가 한 일

Midjourney의 엔지니어 Cheng Lou가 이 30년 된 문제를 정면으로 돌파했다. 2026년 3월 27일 공개. 공개 하루 만에 GitHub 5,000스타. 현재 3만 이상. 조회수 1,800만.

이 반응은 이 문제가 얼마나 오래된 페인 포인트였는지를 보여준다.

핵심 아이디어

핵심 아이디어는 의외로 단순하다.

브라우저에는 Canvas라는 그래픽 API가 있다. 주로 차트나 게임 그래픽을 그릴 때 쓰는데, 여기에 measureText라는 함수가 있다. 이 함수는 "이 폰트로 이 글자를 그리면 너비가 얼마냐"를 알려준다.

중요한 건 두 가지다.

  1. DOM 렌더링과 동일한 폰트 엔진을 사용한다. 결과가 같다.
  2. 레이아웃 트리 바깥에서 작동한다. 리플로우 비용이 0이다.

Pretext는 이걸 체계적으로 활용한다.

텍스트가 처음 나타나면, 모든 단어의 너비를 Canvas measureText로 한 번 측정하고 캐시한다. 이게 "준비(prepare)" 단계다. 이 단계에서만 Canvas를 사용한다.

이후의 모든 레이아웃은 순수한 산술 연산이다. 캐시된 너비를 순회하고, 줄 너비를 추적하고, 최대치를 넘으면 줄을 바꾼다. DOM 접근 없음. 리플로우 없음. 레이아웃 트리 참조 없음.

숫자로 보면

30msDOM 방식 (500개 블록)
0.05msPretext (동일 작업)
600x성능 향상
15KB패키지 크기 (의존성 0)

500개 텍스트 블록 측정에 DOM 방식은 15~30밀리초에 500번의 리플로우를 발생시킨다. Pretext는 같은 작업을 0.05밀리초에 리플로우 제로로 수행한다. 300배에서 600배의 성능 향상.

그런데 이 숫자조차 과소평가다. DOM 방식의 비용은 페이지가 복잡해질수록 증가하지만, Pretext의 비용은 페이지 복잡도와 완전히 무관하기 때문이다. 페이지에 요소가 10개든 10,000개든, Pretext의 레이아웃 시간은 동일하다.


직접 보자

아래 데모에서 공을 드래그해보자.

Pretext 데모 로딩 중...

텍스트가 2컬럼으로 흐르면서 공을 실시간으로 피해간다. 인용문 주변으로도 텍스트가 감싸진다. 왼쪽 컬럼에서 넘친 텍스트가 오른쪽 컬럼으로 자연스럽게 이어진다.

이 모든 레이아웃 계산이 매 프레임 일어나고 있다. 상단 바의 LAYOUT 수치를 보면 보통 1밀리초 미만이다. 60fps에 필요한 프레임 예산은 16밀리초. 레이아웃에 1밀리초도 안 쓰고 있으니 나머지 15밀리초는 전부 렌더링과 다른 로직에 쓸 수 있다.

CSS Shapes가 2014년부터 시도했지만 달성하지 못한 것들이다. 양쪽 동시 감싸기. 임의의 도형. 드래그로 실시간 이동. 멀티컬럼 텍스트 핸드오프. 60fps.


이걸 만든 방식이 더 흥미롭다

Cheng Lou는 이 라이브러리를 혼자 만든 게 아니다. Claude Code와 Codex, 두 AI 코딩 에이전트에게 만들게 했다.

방법이 독특하다. 브라우저의 실제 렌더링 결과를 "정답"으로 설정하고, AI가 그 결과를 재현하는 코드를 생성하게 했다. 텍스트를 넣고, 브라우저가 실제로 그려낸 줄바꿈 위치와 높이를 보여주고, "이거랑 똑같이 나오게 만들어"라고 한 것이다.

한 번이 아니다. 수 주 동안 반복했다. 다양한 폰트, 다양한 언어(한국어, 중국어, 아랍어, 태국어, 이모지까지), 다양한 너비에서 테스트하고 또 테스트했다. 최종 결과물은 브라우저의 텍스트 배치와 픽셀 단위로 일치한다.

AI가 단순히 "코드를 대신 짜주는" 수준이 아니라, 브라우저라는 30년 된 시스템의 동작을 학습하고 재현하는 데 쓰인 것이다. 코드를 생성한 게 아니라 시스템을 모사한 거다.

이게 가능했던 건 검증이 명확했기 때문이다. "브라우저가 그리는 것과 같으면 맞고, 다르면 틀리다." 이보다 깔끔한 정답 기준이 있을까. AI에게 정답을 보여주고 반복하게 하는 패턴은 앞으로 비슷한 프로젝트에서 점점 더 많이 쓰일 것 같다.


이게 바꿀 것들

Pretext가 열어주는 건 단순히 "텍스트가 빨라진다"가 아니다.

텍스트 측정이 사실상 무료가 되면, 이전에는 비용 때문에 시도조차 못했던 인터페이스가 가능해진다. 몇 가지만 꼽아보면:

완벽한 가상 스크롤

메시지 앱에서 수만 개의 메시지를 스크롤하려면, 화면 밖에 있는 메시지의 높이를 미리 알아야 한다. 지금은 추정치를 쓰기 때문에 스크롤할 때 메시지가 튀거나 점프하는 현상이 생긴다. Pretext로 정확한 높이를 DOM 없이 계산하면, 시각적 결함이 완전히 사라진다.

인터랙티브 데이터 시각화

차트 위에 라벨이 겹치는 건 데이터 시각화의 오래된 골칫거리다. 텍스트가 차트 요소를 실시간으로 피해가면서 자리를 잡을 수 있다면, 줌/팬할 때마다 라벨이 스스로 최적의 위치를 찾는다.

협업 문서 에디터

여러 사용자가 동시에 이미지나 위젯을 문서 안에 배치하면, 텍스트가 즉시 재배치되는 에디터. Google Docs나 Notion이 아직 해내지 못한 수준의 실시간 레이아웃이 가능해진다.

웹 네이티브 매거진 레이아웃

인쇄 매거진에서만 가능했던 것들. 멀티컬럼 레이아웃에서 텍스트가 사진을 감싸고, 인용문 주변으로 흐르고, 컬럼 간에 자연스럽게 이어지는 편집 레이아웃. 이게 웹에서 인터랙티브하게 동작한다. 독자가 창 크기를 바꿔도, 이미지를 드래그해도, 텍스트는 즉시 재배치된다.


30년의 상자가 열린다

웹에서 텍스트는 30년 동안 "상자 안에 갇힌 존재"였다. 주변 요소에 반응하지 못하고, 동적 레이아웃에 참여하지 못하고, 유연한 구성의 일부가 되지 못했다. 우리가 만드는 앱의 애니메이션은 부드럽고, 인터랙션은 즉각적이고, 그래픽은 화려하다. 하지만 텍스트만은 여전히 딱딱한 상자 안에 앉아서 움직이지 않았다.

Pretext가 바꾸는 건 텍스트의 속도가 아니다. 텍스트의 지위다. 정적인 콘텐츠에서, 레이아웃에 실시간으로 참여하는 동적 요소로.

15킬로바이트. 의존성 제로. DOM 읽기 제로.

그리고 텍스트는 흐르기 시작한다.