Skip to content

HazeHash ​

Compact image placeholders: an image becomes a 16–48 byte string (28 by default, 38 base64url characters) from which a blurred preview is rebuilt in a fraction of a millisecond. The string also carries the aspect ratio and, when needed, the alpha channel. The core package works in browsers, Node.js and edge runtimes, with a Vue 3 component, a Nuxt module and a command line on top of it.

Features ​

  • Lower perceptual error at the same size — at 28 bytes the mean error is 49% lower than BlurHash and 20% lower than ThumbHash, measured on 513 photos, screenshots and graphics; see Benchmark
  • A byte budget instead of a grid size — budget is the maximum size of a hash in bytes (16 for the smallest practical hash, 28 by default, 36 and more for detail), and the encoder spends it where the image needs it; simple images come out smaller than the budget
  • Aspect ratio and transparency inside the string — the header stores the ratio, so the box can be sized before the image loads, and an alpha block is added only when the image has transparent pixels
  • A better colour model — OKLab colour, an orthogonal DCT basis, separate luma and chroma grids, rate-distortion optimised quantisation and Golomb–Rice coding; see Hash Format
  • No runtime dependencies — the core never touches the DOM, window or Buffer, so it runs in browsers, Node.js 20+, Cloudflare Workers and other runtimes; reading image files in Node.js uses the optional peer sharp
  • Deterministic and unchanging — the same input and options always give the same bytes, and version 1 decoding does not change between releases, so a stored hash keeps decoding the same way
  • Tree-shakable entry points — the decoder is about 2.6 KB gzip, the encoder about 6.3 KB, and the canvas helper adds about 0.05 KB, so a browser downloads only what it imports
  • Tolerant of truncation — a cut hash is still valid and decodes with less detail, and a malformed one never hangs or crashes the decoder: it either decodes or throws a PlaceholderError
  • Vue 3 component and Nuxt module — <PlaceholderImage> renders only the average colour and the aspect ratio on the server, so hydration cannot mismatch, and the Nuxt module generates the hashes of your images during the build
  • A command line — hazehash encode, decode and info hash files, folders and globs, draw a preview in the terminal and explain what a string contains

How it works ​

To encode, the image is area-averaged down in linear light to a small analysis grid and converted to OKLab. Luma and the two colour channels get their own grids of DCT coefficients, chosen to fit the image's aspect ratio, and the coefficients are quantised with a rate-distortion search that fits the byte budget. The result is written as a 7-byte header plus Golomb–Rice coded coefficients, and printed as base64url.

To decode, the coefficients are rebuilt from the string, turned back into pixels at the requested size, converted from OKLab to sRGB with gamut mapping, and dithered with a deterministic pattern so the gradients do not band.

Packages ​

HazeHash is published as three npm packages from one repository:

  • hazehash — the encoder, the decoder, the canvas and Node.js helpers and the hazehash command
  • hazehash-vue — the PlaceholderImage component and the usePlaceholder() composable for Vue 3
  • hazehash-nuxt — a Nuxt module that registers the component and generates hashes during the build