- Pretext, DOM erişimi olmadan çok satırlı metnin yüksekliğini ve satır yerleşimini hesaplayan saf JavaScript/TypeScript kütüphanesi olup hem tarayıcıyı hem de sunucu ortamlarını destekler
- getBoundingClientRect gibi DOM ölçüm API'lerini kullanmadığı için yerleşim reflow maliyetini ortadan kaldırır ve font motoru tabanlı kendi ölçüm mantığıyla doğruluğu korur
- prepare() / layout() API'leri üzerinden metni ön işleyip önbelleğe alınmış genişlik verilerini kullanarak saf aritmetik işlemlerle hızlı yükseklik hesaplaması yapar
- Emoji, karışık yönlü metin (bidi), farklı diller desteklenir ve Canvas·SVG·WebGL·sunucu tarafı render ortamlarında da aynı sonuçları verir
- Sanal kaydırma, metin taşması doğrulaması, kayan metin yerleşimi gibi hassas UI yerleşimleri kurmakta kullanılabilecek yüksek performanslı bir metin motorudur
Genel Bakış
- Pretext, çok satırlı metin ölçümü ve yerleşimi için geliştirilmiş saf JavaScript/TypeScript kütüphanesi olup DOM, Canvas, SVG ve sunucu tarafı render desteği sunar
- DOM ölçüm API'lerini (
getBoundingClientRect, offsetHeight vb.) kullanmadığı için yerleşim reflow maliyetini ortadan kaldırır
- Tarayıcının font motorunu temel alan kendi ölçüm mantığı sayesinde doğru ve hızlı performans sağlar
- Tüm dilleri, emojileri, karışık yönlü metni (bidi) destekler ve tarayıcılar arası farkları da ele alır
Kurulum ve Demo
Başlıca Özellikler
- Pretext iki ana kullanım biçimi sunar
-
1. DOM erişimi olmadan paragraf yüksekliği ölçümü
prepare() metni ön işler; boşluk normalizasyonu, segment ayırma, glue kurallarının uygulanması ve canvas tabanlı ölçüm yaparak opak bir handle döndürür
layout() önbelleğe alınmış genişlik verilerini kullanarak saf aritmetik işlemlerle yükseklik ve satır sayısını hesaplar
- Aynı metin ve ayarlarda
prepare() tekrar tekrar çağrılmaz; yeniden boyutlandırmada yalnızca layout() yeniden çalıştırılır
{ whiteSpace: 'pre-wrap' } seçeneğiyle boşluklar, sekmeler (\t) ve satır sonları (\n) olduğu gibi korunur
- Benchmark sonucu:
prepare() yaklaşık 19 ms (500 metin için), layout() yaklaşık 0.09 ms
- Döndürülen yükseklik değeri şu UI işlevlerinde kullanılabilir
- Sanalleştirme ve oklüzyon işlemlerinde doğru yükseklik hesaplama
- JS tabanlı yerleşim sistemleri (ör. masonry, flexbox benzeri yapılar)
- Yapay zeka tabanlı metin taşması doğrulaması
- Metin yüklenirken kaydırma konumunu koruma
-
2. Elle paragraf yerleşimi oluşturma
prepareWithSegments() ile segment düzeyinde veri üretilir
layoutWithLines() sabit genişlikte her satırın metnini ve genişlik bilgisini döndürür
walkLineRanges() metin dizgelerini oluşturmadan her satırın genişliğini ve imleç aralıklarını dolaşır
- Örn: birden çok genişliği test ederek uygun satır sayısı ve yüksekliği bulmak için ikili arama benzeri yerleşim ayarı yapılabilir
layoutNextLine() satır başına genişliğin değiştiği durumlarda satır satır sıralı yerleşim yapar
- Örn: görsel etrafında metin akıtmak için kayan metin yerleşimi
- Bu yaklaşım Canvas, SVG, WebGL, sunucu tarafı render ortamlarında da aynı şekilde uygulanabilir
API Özeti
-
Temel ölçüm API'leri
prepare(text, font, options?): Metni analiz eder ve ölçer, layout() için verilecek handle'ı döndürür
layout(prepared, maxWidth, lineHeight): Verilen genişlik ve satır yüksekliğine göre metin yüksekliği ve satır sayısını hesaplar
-
Elle yerleşim API'leri
prepareWithSegments(text, font, options?): Segment düzeyinde veri döndürür
layoutWithLines(prepared, maxWidth, lineHeight): Her satırın metni, genişliği ve imleç bilgilerini içerir
walkLineRanges(prepared, maxWidth, onLine): Her satırın genişliğini ve imleç aralıklarını callback ile iletir
layoutNextLine(prepared, start, maxWidth): Yerleşimi satır düzeyinde iterator biçiminde yürütür
LayoutLine, LayoutLineRange, LayoutCursor tür tanımları dahildir
-
Diğer yardımcı araçlar
clearCache(): Dahili önbelleği temizler
setLocale(locale?): Locale ayarlar ve önbelleği temizler (mevcut durumu etkilemez)
Kısıtlar ve Dikkat Edilmesi Gerekenler
- Pretext tam teşekküllü bir font render motoru değildir
- Temel hedef CSS özellikleri
white-space: normal
word-break: normal
overflow-wrap: break-word
line-break: auto
{ whiteSpace: 'pre-wrap' } kullanıldığında boşluklar, sekmeler ve satır sonları korunur ve tab-size: 8 uygulanır
- macOS'ta
system-ui fontu layout() doğruluğu için uygun olmadığından açık bir font adı kullanılması önerilir
overflow-wrap: break-word nedeniyle çok dar genişliklerde sözcük içinde de satır kırılabilir, ancak ayırma yalnızca karakter birimi (grapheme) temelinde yapılır
Geliştirme ile İlgili
- Geliştirme ortamı ve komutlar için
DEVELOPMENT.md dosyasına bakın
Katkı ve Arka Plan
- Fikirler, Sebastian Markbage'ın text-layout projesinden devralınmıştır
- canvas
measureText tabanlı shaping, pdf.js'in bidi işleme yaklaşımı ve streaming line breaking tasarımı miras alınarak geliştirilmiştir
1 yorum
Hacker News yorumları
Bu proje gerçekten etkileyici
Web sayfasında metni gerçekten render etmeden satırlara bölünmüş metnin yüksekliğini verimli şekilde hesaplama sorununu çözüyor
Kelime bazında bölünmüş segmentlerin genişliğini ve yüksekliğini önbelleğe alıyor ve tarayıcının satır sonu algoritmasını doğrudan uyguluyor
Tireleme, emoji, Çince gibi farklı karakterlerin işlenmesi ve tarayıcıya göre render farkları (Safari dahil) nedeniyle son derece zor bir iş
Gerçek tarayıcılarla karşılaştırmalı test için corpora veri kümesini ve accuracy test sayfasını kullanıyor
ASCII metin için benim kodum 80ms, pretext ise 2200ms sürüyor
Doğruluğu henüz test etmedim ama bu gece deneyeceğim
Issue #18 içinde performans iyileştirmesi için PR’ler zaten açılmış
Ben de daha önce canvas üzerinde çok satırlı metin render etmeye çalışırken epey uğraşmıştım
Bu proje DOM ile doğrudan bağlantılı olduğu için çok daha kullanışlı
Örnek: Scrawl demosu
Bu, native API’den daha yavaş olabilir ve tarayıcının canvas dışı render’ıyla aynı mantığı kullandığını garanti etmez
Canvas’a render edip ölçme yaklaşımını kullanıyor; daha çok metin yerleşimini analiz etmek için bir API sunuyor
Bu gerçekten uzun zamandır beklenen bir özellik
Eskiden responsive accordion gibi şeyleri düzgün şekilde uygulamak zordu
Web’in gelişim modeli hep ① karmaşık ihtiyaç ortaya çıkar → ② JS/CSS hack’leri gelir → ③ standardizasyona gider şeklinde oldu
Bu kez bunun bir hack değil, düzgün bir 2. aşama olduğunu düşünüyorum
RESEARCH.md dosyasına bakınca tarayıcılar arasındaki emoji ölçüm farklarına kadar ayrıntılı araştırılmış
Bakımı zor olacaktır ama web’in gelişiminde büyük bir dönüm noktası olabilir gibi görünüyor
Bu kez geliştirme sürecinde AI’nin aktif biçimde kullanılmış olması ilginç. Görünüşe göre büyük kısmı Cursor ajanı kullanılarak yapılmış
Kütüphanenin yazarına göre Claude Code ve Codex’e tarayıcının ground truth verileri öğretilmiş, ardından birkaç hafta boyunca yinelemeli ölçümler yapılmış
İlgili tweet bakılabilir
Autoresearch de kısmen kullanılmış gibi görünüyor
Şekil tabanlı reflow örneğini özellikle beğendim
Bunu Ensō(enso.sonnet.io) üzerinde denemek istemiştim ama sadeliği korumak için vazgeçtim
Accordion örneği, CSS
interpolate-sizeile de uygulanabilirJosh Comeau’nun yazısı referans alınabilir
Metin balonu örneği ise
text-wrap: balance | prettyile benzer şekilde yapılabilirbalanceya daprettytam bir çözüm sağlamıyorSatır uzunluklarını eşitlemek çoğu zaman istenen şey değil
İlgili CSSWG issue: #191
text-wrapsatır başına düşen kelime sayısını dengelemeye yardımcı oluyor ama sağ boşluk sorunu hâlâ kalıyorpretext, canvas.measureText’i doğrudan kullanmıyor; metni ve özellikleri JS API’sine verdiğinizde yerleşimi otomatik hesaplıyor
Eskiden ya
measureText’i doğrudan kullanmak ya da harfbuzz’ı tarayıcıya taşımak gerekiyorduBu, teknik bir atılımdan çok mevcut parçaların iyi bir birleşimi gibi görünüyor
Yine de Skia-wasm / Canvaskit ile farkının ne olduğunu merak ediyorum
pretext’in farkı, AI ile saf Typescript tabanlı glif render’ı uygulamış olması
Bu, ffmpeg’i doğrudan C ile yazmakla Dart’tan çağırmak arasındaki fark gibi hissettiriyor
Bu tür denemeler istemci tarafı FOSS için yeni olasılıklar gösteriyor
Geçen yıl HTML ile baskı amaçlı broşür mizanpaj sistemi yapmıştım; satır sonu ve dul satır önleme için Selection API ile kutu sınırlarını tekrar tekrar hesaplıyordum
Hâlâ iyi çalışıyor ama nedenini bilmediğim bir off-by-one hack’i var
pretext’in yinelemeli satır oluşturma özelliği gerçekten sevindirici
Fedora + Firefox ortamında demoların hepsi bozuk görünüyor
Örnek: ekran görüntüsü
Böyle bir özellik aslında tarayıcı standardı API olarak sunulmalı
W3C’ye özellik talebi göndermek için ne yapmak gerektiğini, topluluk oylaması gibi bir şeyin mümkün olup olmadığını merak ediyorum
Ama tarayıcı üreticileri buna öncelik vermiyor
Şu anda Chrome daha çok AI ile ilgili API’lere odaklanmış durumda
Sciter motorunda zaten Graphics.Text özelliği var
CSS stillerini doğrudan uygulayabilen canvas tabanlı bir metin render öğesi
Tarayıcının metin araması (Ctrl+F) sanal kaydırmalı listelerde düzgün çalışmıyor
Bu tür sorunları çözmek için JS yerine yeni bir “Search” API’si gerekebilir
İlgili projeler: Display Locking, MDN belgesi
Sanallaştırılmış listenin ekran dışındaki öğeleri DOM’da olmadığı için aranamaz
Bunu çözmek için seçim, odak, kaydırma konumu ve eşleşme gezinmesini kapsayan yeni bir tarayıcı sözleşmesi gerekir
Ama sitelerin bunu tutarlı biçimde kullanma ihtimali düşük