npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

visionary-image-js

v1.1.0

Published

Drop-in Blurhash placeholders for any website. Eliminate layout shift and improve Core Web Vitals — via script tag or SSR HTML.

Downloads

338

Readme

visionary-image-js

NPM version GitHub Actions Workflow Status NPM bundle size NPM Downloads

Drop-in Blurhash placeholders for any website. Point an <img> at a Blurhash URL, include the script, and images get a blur preview with a reserved layout box — eliminating Cumulative Layout Shift (CLS) and improving Core Web Vitals.

See our PageSpeed Insights Report →

Lighthouse filmstrip showing the three-layer load: background color → Blurhash → full image:

Lighthouse report loading stage filmstrip

Features

  • No markup changes: Any <img> with a Blurhash URL in its src is automatically upgraded.
  • Zero CLS: Dimensions are read from the URL so space is reserved before layout — no Cumulative Layout Shift when the image loads.
  • Works with dynamic pages: New images and src updates are observed automatically (SPAs included).
  • Server rendering: Generate the same markup server-side for Hono, Express, and friends.
  • Shared cache: Each Blurhash is decoded once, even across multiple copies of the bundle.

Installation

pnpm add visionary-image-js
npm install visionary-image-js

Quick start

Load the script from <head> without defer or async. It decorates each image as the HTML parser reaches it. It can run later, but you may experience layout shift.

<head>
  <script src="https://unpkg.com/visionary-image-js/dist/visionary-autoload.js"></script>
</head>
<body>
  <img
    src="https://blurhash.link/image/aW1nIzQyITk2MCE3MjAhODY5NmFjIUFVRlpULiVMX04lMQ/photo.jpg"
  />
</body>

Any <img> whose src is a Blurhash URL is wrapped and given a blur placeholder. Create Blurhash URLs with Visionary URL Maker or the blurhash-url package.

Autoload options

| Attribute | Effect | | --------------------- | ------------------------------------------------------------------------ | | data-target=".blur" | Only decorate images matching this CSS selector (default: img) | | data-eager-canvas | Paint Blurhash canvases synchronously (better for above-the-fold images) | | data-once | Initialize once at DOM ready instead of observing for new images | | data-debug | Enable debug logging |

<script
  src="https://unpkg.com/visionary-image-js/dist/visionary-autoload.js"
  data-target=".blur"
  data-eager-canvas
></script>

To opt-out an image, add the data-visionary-skip attribute on your <img> element.

Usage

Initialize manually

import { initVisionaryImages } from "visionary-image-js";

initVisionaryImages();

Watch for new images

For SPAs or pages that add images after load:

import { observeVisionaryImages } from "visionary-image-js";

const observer = observeVisionaryImages();

// Later (like page transition, unmount)
observer.disconnect();

The autoload script uses observeVisionaryImages by default (unless data-once is set).

Options

Both functions accept the same options:

initVisionaryImages({
  bgColorAlpha: 0.7, // Background color opacity
  canvasSize: 24, // Blurhash canvas size
  debug: false, // Enable debug logging
  eagerCanvasPaint: true, // Paint synchronously instead of waiting for requestAnimationFrame
  endpoint: undefined, // Serve images from your own domain
  punch: 1, // Blurhash punch parameter
  root: document.body, // Element to search within
  target: "img", // CSS selector to target specific images
});

SSR rendering

import { renderVisionaryHTML } from "visionary-image-js";

const { html, state } = renderVisionaryHTML(blurhashUrl, {
  alt: "My image",
});

//  html → <div data-visionary /> container with a nested canvas and image element
// state → parsed values such as aspectRatio, backgroundColor, blurhash code

API

initVisionaryImages(options?)

Enhance matching <img> elements whose src is a Blurhash URL. Returns the number of elements queued. Images are wrapped immediately so layout is reserved; canvas painting is deferred via requestAnimationFrame unless eagerCanvasPaint is set.

observeVisionaryImages(options?)

Same as above, plus a MutationObserver for images added later or whose src changes. Returns the observer so you can disconnect() it.

renderVisionaryHTML(src, options?)

Render a Visionary image as an HTML string for SSR. Returns { html, state }.

Options:

  • alt — Image alt text
  • bgColorAlpha — Background color opacity (default: 0.7)
  • canvasSize — Canvas dimensions (default: 24)
  • className — CSS class for the container
  • debug — Enable debug logging
  • disableBlurLayer — Omit the blur (canvas) layer
  • disableImageLayer — Omit the image layer
  • endpoint — Serve images from your own domain
  • hideImageLayer — Hide the image via CSS (reveals the blur underneath)
  • loading"lazy" (default) or "eager"
  • size — Override the size token from the Blurhash URL

computeImageState(src, options?)

Parse a Blurhash URL and compute dimensions, background color, source, and (in the browser) decoded pixels.

decodeWithCache(hash, size?, punch?)

Decode a Blurhash string to pixel data, using the global cache.

clearCache()

Clear the global pixel cache.

Global cache

In the browser, decoded Blurhash pixels are cached in window.V7Y_PIXEL_CACHE, so:

  • The same image isn't decoded twice
  • The cache is shared across multiple bundle copies
  • You can empty it with clearCache()

Related packages

| Package | Use for | | -------------------------------------------------------------------- | ------------------------------------------------------------------ | | visionary-image-js (this package) | Zero-config <script> / CDN, or framework-agnostic SSR HTML | | visionary-image | React apps (<Image />) and the <visionary-image> web component |

License

ISC