4 puan yazan GN⁺ 2026-03-30 | 1 yorum | WhatsApp'ta paylaş
  • 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

 
GN⁺ 2026-03-30
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

    • Ben de buna benzer bir şey yapmıştım. AI olmadan geliştirilmiş, uWrap.js adında 2KB’lık basit bir sürüm
      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ış
    • Metin yerleşim motorları gerçekten kötü şöhretli derecede zor
      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
    • Açıklamaya bakılırsa aslında segmentleri canvas üzerinde render edip ölçüyor gibi görünüyor
      Bu, native API’den daha yavaş olabilir ve tarayıcının canvas dışı render’ıyla aynı mantığı kullandığını garanti etmez
    • Aslında tarayıcının metin render algoritmasını birebir yeniden uygulamış değil
      Canvas’a render edip ölçme yaklaşımını kullanıyor; daha çok metin yerleşimini analiz etmek için bir API sunuyor
    • Remotion videoları için dinamik altyazı hazırlarken metin yüksekliğini hesaplamak yüzünden çok uğraşmıştım; bu kütüphane büyük yardım sağlayacak gibi duruyor
  • 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

    • Responsive accordion artık CSS ile mümkün ama yine de böyle bir API’ye ihtiyaç vardı
      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-size ile de uygulanabilir
    Josh Comeau’nun yazısı referans alınabilir
    Metin balonu örneği ise text-wrap: balance | pretty ile benzer şekilde yapılabilir

    • Ama balance ya da pretty tam bir çözüm sağlamıyor
      Satır uzunluklarını eşitlemek çoğu zaman istenen şey değil
      İlgili CSSWG issue: #191
    • text-wrap satır başına düşen kelime sayısını dengelemeye yardımcı oluyor ama sağ boşluk sorunu hâlâ kalıyor
  • pretext, 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 gerekiyordu
    Bu, 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

    • Fark basit: pretext, wasm değil
    • Skia devasa bir render motoru. Flutter’daki gibi cihazdan bağımsız bir render API’si sağlıyor
      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
    • Eğer yazar haklıysa bu, web GUI framework’leri ve zengin metin editörleri için büyük değişiklik yaratacak
  • 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ü

    • Bu tür projelerin sonuçta bitmeyen edge case takibi olduğunu gösteriyor
  • 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

    • Zaten bir Font Metrics API önerisi var
      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

    • Bir Virtual Scroller API vardı ama neredeyse hiç ilerleme olmadı
      İlgili projeler: Display Locking, MDN belgesi
    • Native arama yalnızca DOM’da bulunan düğümleri tarar
      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