Reference
Architecture
Three npm packages share one core. hazehash holds the whole codec: an encoder that downsamples the image in linear light, converts it to OKLab and describes it with separate luma and chroma DCT grids, picks the quantisation with a rate-distortion search that fits the byte budget, and writes the coefficients with Golomb–Rice coding, and a decoder that does the reverse. It also contains the thin platform layers: hazehash/canvas (draws into a canvas), hazehash/node (reads image files through the optional peer sharp) and the hazehash command. The core files never touch window, document, Buffer, eval or dynamic import(), and a test enforces it.
hazehash-vue is a small layer on top of the decoder: a usePlaceholder() composable that holds the colour, the aspect ratio and a canvas ref, and a PlaceholderImage component built on it. hazehash-nuxt registers that component, scans your image folders at build time with hazehash/node, caches the hashes by file size and modification time, and exposes them to the component as a virtual module.
The format of a hash is documented on Hash Format, and the choices behind it are measured on Benchmark.
SSR compatibility
The decoder and the encoder are plain functions without environment access, so they run on a server. What needs a browser is drawing into a canvas. The Vue component and the composable are written for server rendering: on the server they produce only background-color (the average colour) and aspect-ratio, and the canvas is added after mount, so the server markup and the first client render are identical and hydration cannot mismatch. No <ClientOnly> wrapper is needed, in Nuxt or elsewhere.
Accessibility
The canvas with the blurred preview is decorative and is marked aria-hidden="true", so assistive technology reads only the real image and its alt text. The fade-in of the real image is turned off when the visitor prefers reduced motion (prefers-reduced-motion: reduce).
Bundle size & peer dependencies
The sizes are minified and gzipped, and include the shared code each entry point imports:
hazehashandhazehash/decode— about 2.6 KBhazehash/encode— about 6.3 KBhazehash/canvas— about 0.05 KB on top of the decoder
Every package ships sideEffects: false, so a bundler keeps only what you import. hazehash has no runtime dependencies and one optional peer, sharp (>=0.33), used only by hazehash/node, the command line and the Nuxt module's build-time generation. hazehash-vue has the peers hazehash and vue (^3.3.0). hazehash-nuxt depends on @nuxt/kit, hazehash and hazehash-vue, and has the peers nuxt (^3.9.0) and the optional sharp. All three support Node.js 20 and newer.
Comparison
HazeHash does the same job as BlurHash and ThumbHash: a short string that stands in for an image until it loads.
- Quality — at the same size HazeHash has a mean perceptual error about 49% lower than BlurHash and 20% lower than ThumbHash, and at 20 bytes, the size of a ThumbHash, it is still 14% better. See Benchmark.
- Size — a budget from 16 to 48 bytes, 28 by default, against ThumbHash's native output of about 21 bytes and BlurHash's strings, which grow with the grid.
- Transparency — the alpha channel is stored only when the image needs it.
- Aspect ratio — stored in the header, so the box can be sized from the hash alone.
- Format — a new format, not compatible with either of them; a HazeHash cannot be decoded as a BlurHash or a ThumbHash and the other way round. Existing hashes have to be created again from the source images.
Development
A pnpm workspace with packages/core, packages/vue and packages/nuxt, plus a Nuxt demo, benchmark scripts, examples and end-to-end tests. Building needs Node.js 22 and pnpm.
pnpm install
pnpm build # all packages
pnpm test # builds, then the unit tests of core, vue and nuxt
pnpm typecheck
pnpm lint
pnpm e2e # Chromium, Firefox, WebKit, Cloudflare Workers runtime, Nuxt SSR
pnpm demo # a Nuxt app with 17 images next to their placeholders
pnpm bench # the full benchmarkThe core package also has size (bundle sizes), fuzz and make-vectors (the frozen conformance vectors, which refuses to overwrite them).
License
MIT.