Overview
A production-grade image layout engine built from scratch in a Turborepo — Pinterest masonry, Airbnb justified galleries, and fixed grids behind one swappable API, with custom virtualization, progressive loading, and a steady 60 FPS at 5,000 images. No layout libraries.
These docs are written in MDX and rendered with @next/mdx.
Architecture at a glance
The codebase separates concerns into pure, tested packages and a thin app that only composes them:
| Package | Responsibility |
|---|---|
@repo/utils | Shared types, seeded dataset generator, schedulers (rafThrottle, onIdle) |
@repo/masonry-engine | O(n) masonry + incremental append + Web Worker |
@repo/justified-layout | Justified rows + fixed-aspect grid |
@repo/image-loader | ProgressiveImage, picsum loader, idle prefetch |
@repo/ui | Design system + useVirtualGrid / useContainerSize / useInfiniteImages |
The one API
Every engine implements the same contract, so renderers and virtualization stay engine-agnostic:
interface LayoutEngine<O> {
name: "masonry" | "justified" | "fixed-grid";
compute(images: ImageData[], containerWidth: number, options: O): LayoutResult;
}
// LayoutResult = { positions: PositionedImage[]; containerHeight: number }Swapping engines is a single call — see the live demo on the home page and the benchmark.
What to read next
- Layout engines — the masonry, justified, and fixed-grid algorithms.
- Virtualization — how 5,000 images stay at a few dozen DOM nodes.
- Image loading — the blur → full progressive pipeline.
- Hooks — the React API.
- Performance & a11y — the guarantees and how they're kept.