Geometric image placeholders for Svelte 5
No blur. The placeholder is the image, approximated by geometric shapes fitted at build time — and because they're stored in fit order, replaying them makes the picture visibly sharpen until the real photo takes over, cut into the same shapes.
In production on szkolyjogi.pl — 700+ listing photos resolve from their geometric preview — and kurcz.pl.
A page of photos
Photos on Unsplash by Marat Gilyadzinov, Alexey Topolyanskiy, Samuel Scrimshaw, veeterzy, Andrew Coelho, André Spieker.
Playground

takeShapes(placeholder, n) sends only the first n- Inline placeholder
- 2.6 KB 2.6 raw
- Lighter first paint
- — vs. the photo
- Shapes
- 100 in fit order
- Fit time
- build prebuilt
Presets
triangles 2.6 KBlow-poly 2.6 KBsoft 2.3 KBmosaic 1.9 KBbubbles 1.7 KBHow it works
- 01
Fit at build time
A Vite plugin fits geometric shapes to each
?geometrizeimport — cached on disk by content hash, so clean rebuilds skip work you've already done. Or batch CMS photos withnpx svelte-geometrize. The expensive part never ships. - 02
Paint instantly, no layout shift
The placeholder is inline in the server-rendered HTML, so a real preview fills the box before the photo's first byte arrives — and because its aspect ratio is reserved, nothing below it ever jumps.
- 03
Reveal, then hand off
revealMspaces the shapes across a fixed budget; pure CSS plays before hydration and respects reduced motion. Then the photo opens through the same shapes, smallest first, and fills the gaps between them. Nothing is ever half see-through.
Use it
import { GeometrizedImage } from '@nomideusz/svelte-geometrize';
import placeholder from './photo.jpg?geometrize';
import src from './photo.jpg';
<GeometrizedImage {placeholder} {src} alt="Sunset over mountains" revealMs={850} />
// a named look: './photo.jpg?preset=soft&geometrize'
// build / ingest also need: pnpm add -D sharp
// npx svelte-geometrize ./photos --out ./placeholdersFull options and the Node API are in the docs.