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 읽기도 없다.

이제 웹에서도 텍스트가 주변 요소를 따라 흐를 수 있다.