Demos

Each demo has per-panel Run buttons — click one side at a time to feel the click-to-layout delay. Photos are committed locally (~1-3MB PNGs) so cache-busting is honest and there's no CDN redirect chain skewing the numbers.

Masonry grid

Up to 90 photos, two grids. Left: stock <img> tags — column grows as each image decodes, every tile below shifts. Right: prepare() measures every image, a shortest-column layout commits in one pass, dominant-color placeholders hold the spot.

Editorial article with floats

Three floated figures inside flowing paragraph text. Naive HTML reflows as each figure decodes. Pretext + preimage measures up front and flows the text around the measured rects via flowColumnWithFloats.

Time to first sizing

One ~3MB local PNG loaded three ways: naive <img src>, declared width/height attrs, and prepare(). The timestamp shows when each strategy knows the dimensions.

Decode pool for canvas timelines

Sixteen ~1-3MB PNG frames scrubbable on a canvas. Left decodes on every scrub on the main thread; right warms a DecodePool up front and each scrub is a single cached-bitmap blit.

Scale — hundreds of tiles

Up to 500 cache-busted tiles, naive vs PrepareQueue + dimsOnly + IntersectionObserver. Measured panel takes header bytes for all tiles, lays out the whole grid, then full-fetches only what scrolls into view. Bytes-transferred readout shows what the library saves.

Virtual — ten thousand tiles, DOM-recycled

The chicken-and-egg of windowing: you need heights to position items, but heights come from loading them. Crank to 10k tiles — naive side opens 10k parallel fetches and the CSS column layout thrashes on every arriving image. Measured side probes dims-only, packs the full layout synchronously, and recycles ~40 DOM nodes as you scroll. Scrollbar is honest from frame one.

Manifest — build-time dimensions, instant layout

Cold prepare(url) versus recordKnownMeasurement hydrated from a preimage-manifest JSON. Same 34 photos, same cache-bust, same layout. Cold pays a network probe per URL. Hydrated resolves every prepare() synchronously from cache — layout commits in microseconds.

Stream — reserve space mid-stream

Same photo streamed to both panels under a throttle (simulates a WebSocket, AI-gen feed, or slow CDN). Left buffers every byte, builds a Blob, sets img.src, and only then knows the size — space pops in at the end. Right pipes the same stream through probeImageStream: the first chunk's header fires onDims, space reserves mid-stream, the final Blob renders into it when the stream drains.

Drop zone — Blob inputs

Drag images from your desktop. Left panel inlines them as naive <img> — each file's width is unknown until decode, so surrounding text shifts. Right panel runs prepare(file) — byte-probe on the first 4KB of the blob, ~5ms — and writes the exact width into the <img> before insert.

Chat — pretext rich-inline

A chat bubble with text, avatar icons, stickers, and photo attachments mixed inline. inlineImage turns each image into a pretext RichInlineItem with its measured width reserved as extraWidth. Drag the bubble-width slider — text rebreaks and images shuffle to new positions in one synchronous flow pass.