- Pretext adalah library JavaScript/TypeScript murni untuk menghitung tinggi dan susunan baris teks multiline tanpa akses DOM, serta mendukung lingkungan browser maupun server
- Karena tidak menggunakan API pengukuran DOM seperti getBoundingClientRect, library ini menghilangkan biaya reflow layout dan menjaga akurasi dengan logika pengukuran internal berbasis mesin font
- Melalui API prepare() / layout(), teks dipraproses lalu perhitungan tinggi yang cepat dilakukan dengan operasi aritmetika murni menggunakan data lebar yang telah di-cache
- Mendukung emoji, teks dengan arah campuran (bidi), dan berbagai bahasa, serta memberikan hasil yang sama di Canvas, SVG, WebGL, dan server rendering
- Ini adalah mesin teks berperforma tinggi yang dapat digunakan untuk implementasi layout UI presisi seperti virtualized scrolling, validasi text overflow, dan penempatan teks mengambang
Ikhtisar
- Pretext adalah library JavaScript/TypeScript murni untuk pengukuran dan tata letak teks multiline, dengan dukungan untuk DOM, Canvas, SVG, hingga server-side rendering
- Tidak menggunakan API pengukuran DOM (
getBoundingClientRect, offsetHeight, dll.), sehingga menghilangkan biaya reflow layout
- Memberikan akurasi dan performa tinggi melalui logika pengukuran internal yang mengacu pada mesin font browser
- Mendukung semua bahasa, emoji, dan teks dengan arah campuran (bidi), serta menangani perbedaan antar-browser
Instalasi dan demo
Fitur utama
- Pretext menyediakan dua pola penggunaan utama
-
1. Mengukur tinggi paragraf tanpa akses DOM
prepare() mempraproses teks, melakukan normalisasi spasi, pemisahan segmen, penerapan aturan glue, dan pengukuran berbasis canvas untuk mengembalikan opaque handle
layout() menggunakan data lebar yang telah di-cache untuk menghitung tinggi dan jumlah baris dengan operasi aritmetika murni
- Untuk teks dan konfigurasi yang sama,
prepare() tidak perlu dipanggil berulang; saat resize cukup jalankan kembali layout()
- Opsi
{ whiteSpace: 'pre-wrap' } mempertahankan spasi, tab(\t), dan line break(\n) apa adanya
- Hasil benchmark:
prepare() sekitar 19ms (berdasarkan 500 teks), layout() sekitar 0.09ms
- Nilai tinggi yang dikembalikan dapat digunakan untuk fitur UI seperti:
- Perhitungan tinggi yang akurat pada virtualization dan occlusion handling
- Sistem layout berbasis JS (misalnya masonry, struktur mirip flexbox)
- Validasi text overflow berbasis AI
- Mempertahankan posisi scroll saat teks dimuat
-
2. Menyusun tata letak paragraf secara manual
prepareWithSegments() menghasilkan data per segmen
layoutWithLines() mengembalikan teks dan informasi lebar untuk tiap baris pada lebar tetap
walkLineRanges() menelusuri lebar dan rentang kursor tiap baris tanpa membentuk string teks
- Contoh: memungkinkan penyesuaian layout dengan binary search untuk menguji beberapa lebar dan menemukan jumlah baris serta tinggi yang sesuai
layoutNextLine() menyusun layout satu per satu ketika lebar tiap baris berbeda
- Contoh: penempatan teks mengambang untuk membuat teks mengalir di sekitar gambar
- Pendekatan ini dapat diterapkan dengan hasil yang sama pada Canvas, SVG, WebGL, dan server-side rendering
Ringkasan API
-
API untuk pengukuran dasar
prepare(text, font, options?): menganalisis dan mengukur teks, lalu mengembalikan handle untuk diberikan ke layout()
layout(prepared, maxWidth, lineHeight): menghitung tinggi teks dan jumlah baris sesuai lebar dan tinggi baris yang diberikan
-
API untuk layout manual
prepareWithSegments(text, font, options?): mengembalikan data per segmen
layoutWithLines(prepared, maxWidth, lineHeight): mencakup teks, lebar, dan informasi kursor tiap baris
walkLineRanges(prepared, maxWidth, onLine): mengirimkan lebar dan rentang kursor tiap baris melalui callback
layoutNextLine(prepared, start, maxWidth): melakukan layout dalam bentuk iterator per baris
- Menyertakan definisi tipe
LayoutLine, LayoutLineRange, LayoutCursor
-
Utilitas lainnya
clearCache(): menginisialisasi ulang cache internal
setLocale(locale?): mengatur locale dan menginisialisasi ulang cache (tidak memengaruhi state yang sudah ada)
Batasan dan hal yang perlu diperhatikan
- Pretext bukan mesin rendering font yang sepenuhnya lengkap
- Properti CSS target dasar
white-space: normal
word-break: normal
overflow-wrap: break-word
line-break: auto
- Saat menggunakan
{ whiteSpace: 'pre-wrap' }, spasi, tab, dan line break dipertahankan, dengan tab-size: 8 diterapkan
- Pada macOS, font
system-ui tidak cocok untuk akurasi layout(), sehingga disarankan memakai nama font eksplisit
- Karena
overflow-wrap: break-word, pada lebar yang sangat sempit pemenggalan bisa terjadi di dalam kata, tetapi tetap hanya dipisahkan berdasarkan unit karakter grapheme
Terkait pengembangan
- Untuk lingkungan pengembangan dan perintah yang tersedia, lihat
DEVELOPMENT.md
Kontribusi dan latar belakang
- Melanjutkan ide dari proyek text-layout milik Sebastian Markbage
- Mewarisi dan mengembangkan arsitektur yang dibangun di atas shaping berbasis canvas
measureText, penanganan bidi dari pdf.js, dan desain streaming line breaking
1 komentar
Komentar Hacker News
Proyek ini benar-benar mengesankan
Ini memecahkan masalah menghitung tinggi teks yang dibungkus baris secara efisien tanpa benar-benar merender teks di halaman web
Proyek ini menyimpan cache lebar dan tinggi segmen yang dipecah per kata, lalu mengimplementasikan sendiri algoritme line break browser
Ini pekerjaan yang sangat sulit karena harus menangani berbagai jenis karakter seperti tanda hubung, emoji, bahasa Tionghoa, serta perbedaan rendering antar-browser, termasuk Safari
Untuk pengujian terhadap browser nyata, digunakan dataset corpora dan halaman uji akurasi
Untuk teks ASCII, kode saya butuh 80ms, sedangkan pretext 2200ms
Akurasinya belum saya uji, tapi malam ini saya berencana mencobanya
PR peningkatan performa sudah dibuka di issue #18
Dulu saya juga pernah kesulitan saat mencoba merender teks multiline di canvas
Proyek ini jauh lebih berguna karena terhubung langsung dengan DOM
Contoh: demo Scrawl
Ini bisa lebih lambat daripada API native, dan tidak ada jaminan menggunakan logika yang sama dengan rendering browser non-canvas
Pendekatannya adalah merender ke canvas lalu mengukurnya, jadi lebih seperti API untuk analisis layout teks
Ini benar-benar fitur yang sudah lama ditunggu
Sejak dulu sulit mengimplementasikan hal seperti accordion responsif dengan benar
Pola evolusi web selalu seperti ini: ① kebutuhan kompleks muncul → ② hack JS/CSS → ③ standardisasi
Kali ini rasanya bukan sekadar hack, melainkan tahap 2 yang benar-benar matang
Jika melihat RESEARCH.md, bahkan perbedaan pengukuran emoji antar-browser pun diteliti dengan rinci
Perawatannya pasti berat, tapi ini terasa seperti titik balik besar bagi perkembangan web
Yang menarik, kali ini AI dipakai aktif dalam proses pengembangan. Sepertinya sebagian besar implementasi dibuat memakai agen Cursor
Menurut pembuat library, Claude Code dan Codex diberi ground truth data browser untuk dipelajari, lalu pengukuran diulang selama beberapa minggu
Lihat tweet terkait
Sepertinya Autoresearch juga dipakai sebagian
Saya terutama suka contoh reflow berbasis shape
Saya sempat ingin menerapkannya di Ensō(enso.sonnet.io), tetapi saya menahan diri demi menjaga kesederhanaan
Contoh accordion juga bisa dibuat dengan CSS
interpolate-sizeLihat artikel Josh Comeau
Contoh gelembung teks juga bisa dibuat dengan cara serupa memakai
text-wrap: balance | prettybalanceatauprettybukan solusi lengkapSering kali kita tidak ingin panjang tiap baris dibuat rata
Issue CSSWG terkait: #191
text-wrapmemang membantu menyamakan jumlah kata per baris, tetapi masalah ruang kosong di sisi kanan tetap adapretext tidak memakai canvas.measureText secara langsung; Anda cukup mengirim teks dan atributnya ke API JS, lalu layout dihitung otomatis
Dulu kita harus langsung memakai measureText atau memindahkan harfbuzz ke browser
Ini terasa bukan terobosan teknis besar, melainkan hasil dari menggabungkan elemen-elemen yang sudah ada dengan baik
Tapi saya penasaran bedanya dengan Skia-wasm / Canvaskit
Ia menyediakan API rendering independen-perangkat seperti Flutter
Perbedaan pretext adalah implementasi rendering glyph berbasis TypeScript murni dengan bantuan AI
Rasanya seperti perbedaan antara mengimplementasikan ffmpeg langsung dalam C dan memanggilnya dari Dart
Upaya seperti ini menunjukkan kemungkinan baru bagi FOSS sisi klien
Tahun lalu saya membuat sistem tata letak brosur cetak berbasis HTML, dan untuk line break serta pencegahan widow/orphan saya berulang kali menghitung batas kotak dengan Selection API
Sampai sekarang masih berjalan baik, tetapi ada hack off-by-one yang alasannya sendiri saya tidak pahami
Fitur pembuatan baris iteratif di pretext benar-benar terasa sangat disambut
Di Fedora + Firefox, semua demo terlihat rusak
Contoh: screenshot
Fitur seperti ini seharusnya memang disediakan sebagai API standar browser
Saya penasaran bagaimana cara mengajukan permintaan fitur ke W3C, dan apakah ada semacam voting komunitas
Tetapi vendor browser tidak menaruh prioritas di sana
Saat ini Chrome tampaknya lebih fokus pada API terkait AI
Di mesin Sciter sudah ada fitur Graphics.Text
Ini adalah elemen rendering teks berbasis canvas yang bisa langsung menerapkan style CSS
Pencarian teks browser (Ctrl+F) tidak bekerja dengan baik pada daftar virtual scroll
Untuk menyelesaikan masalah seperti ini, mungkin dibutuhkan API “Search” baru, bukan sekadar JS
Proyek terkait: Display Locking, dokumentasi MDN
Item off-screen dalam daftar tervirtualisasi tidak ada di DOM, jadi tidak bisa dicari
Untuk menyelesaikannya dibutuhkan kontrak browser baru yang mengintegrasikan seleksi, fokus, posisi scroll, dan navigasi hasil cocok
Tetapi kecil kemungkinan situs-situs akan memakainya secara konsisten