Performance & accessibility
Performance budget
| Technique | Where | Effect |
|---|---|---|
translate3d (not top/left) | VirtualCanvas | GPU-composited; transform-only motion |
| State only on band crossing | useVirtualGrid | Refs hold scroll → no per-frame renders |
| Incremental masonry append | useMasonry | O(delta) appends vs O(n) recompute |
| Spatial bands | virtual-window | O(1)/frame windowing; tiny index memory |
| Web Worker layout | useMasonryWorker | Off main thread (slim payload across the boundary) |
| Pre-known dimensions | dataset | Zero CLS |
next/font + optimizePackageImports | app | Smaller bundles, no layout-shifting fonts |
Verify it live on the benchmark: FPS, frame time, visible tiles, DOM nodes, JS heap, layout time, scroll velocity, and long tasks under 1k–5k images.
Animation contract
Only transform and opacity are animated; layout properties never are. Every animation has
a prefers-reduced-motion off-switch (plus a global safety-net in the design tokens).
| Interaction | Property | Duration | Easing |
|---|---|---|---|
| Image appears | opacity | 150ms | ease-out |
| Tile moves (resize / swap) | transform | 220ms | ease-in-out |
| Hero reveal | opacity + transform | staggered | ease-out |
Accessibility
- Meaningful
alttext on every image; semantic landmarks and a skip link. - Arrow-key spatial navigation across tiles; reaching the overscan edge nudges the scroll to reveal more.
- Focus-trapped lightbox with
Escand arrow support; visible focus rings throughout. - Full
prefers-reduced-motionsupport; hover effects gated to hover-capable devices.
Verification
bun test # 46 unit tests — algorithms, windowing, edges
bun run type-check
bun run lint
bun run build
npx react-doctor@latest # React-correctness score (gated in CI)