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

webgl-filters

v0.8.1

Published

GPU-accelerated image filters using WebGL shaders

Downloads

974

Readme

glFilters

GPU-accelerated image filters using WebGL shaders. Every filter runs as a fragment shader.

API Docs

Install

npm install webgl-filters

Usage

import { glFilters, brightness, saturate, blur, invert, customShader } from "webgl-filters";

// Build a filter chain and apply it to an image
const result = glFilters()
  .addFilter(brightness({ amount: 0.1 }))
  .addFilter(saturate({ factor: 1.5 }))
  .addFilter(blur())
  .apply(imageData);
// result is { data: Uint8ClampedArray, width, height }

Direct image/canvas input

apply() accepts ImageData, HTMLImageElement, HTMLCanvasElement, or ImageBitmap directly:

// From an <img> element
const img = document.querySelector("img");
const result = glFilters()
  .addFilter(brightness({ amount: 0.1 }))
  .apply(img);

// From a <canvas> element
const canvas = document.querySelector("canvas");
const result = glFilters()
  .addFilter(blur())
  .apply(canvas);

Filtering from a URL

Use applyAsync() to load an image from a URL and apply filters in one step:

const result = await glFilters()
  .addFilter(brightness({ amount: 0.1 }))
  .addFilter(saturate({ factor: 1.5 }))
  .applyAsync("/photo.jpg");

A standalone loadImage() helper is also exported:

import { loadImage } from "webgl-filters";
const img = await loadImage("/photo.jpg");

Video filtering

Use .compile() to cache shader programs, then .apply() a <video> element. This renders to a canvas at full frame rate with no CPU readback. Video processing is not supported server-side, but you can manually apply filters to video frames if desired.

import { glFilters, brightness, blur } from "webgl-filters";

const filter = glFilters()
  .addFilter(brightness({ amount: 0.1 }))
  .addFilter(blur())
  .compile();

const video = document.getElementById("my-video") as HTMLVideoElement;
const canvas = filter.apply(video); // returns a <canvas> with a rAF loop
document.body.appendChild(canvas);

// Later: stop the loop and release GPU resources
filter.stop();
filter.dispose();

.compile() also speeds up batch image processing by reusing compiled shaders:

const filter = glFilters()
  .addFilter(brightness({ amount: 0.1 }))
  .compile();

const r1 = filter.apply(image1);
const r2 = filter.apply(image2);
filter.dispose();

Providing your own WebGL context

The gl parameter is optional. If omitted, a canvas and context are created automatically. You can still pass one explicitly:

const gl = canvas.getContext("webgl");
const result = glFilters(gl)
  .addFilter(brightness({ amount: 0.1 }))
  .apply(imageData);

For Node.js (headless), install the gl package:

import createGL from "gl";
const gl = createGL(width, height, { preserveDrawingBuffer: true });

Filters

| Filter | Parameters | Description | |--------|-----------|-------------| | alphaUnder({ r, g, b, a? }) | RGBA 0–255 (a defaults to 255) | Composites image over a solid background color | | brightness({ amount }) | amount: float (0 = no change) | Adds to RGB channels | | contrast({ factor }) | factor: float (1.0 = no change) | Scales around midpoint | | saturate({ factor }) | factor: float (1.0 = no change, 0 = grayscale) | Adjusts color saturation | | invert() | — | Inverts RGB channels | | blur({ radius?, strength? }) | radius: px (default 2), strength: 0–1 (default 1) | Gaussian blur — radius sets kernel size, strength blends with original | | threshold({ cutoff? }) | cutoff: 0–1 (default 0.5) | Binary black/white based on luminance | | dilate({ radius? }) | radius: px (default 1) | Morphological dilation — expands bright regions | | erode({ radius? }) | radius: px (default 1) | Morphological erosion — shrinks bright regions | | sharpen() | — | 5×5 sharpening | | convolve({ kernel, divisor?, bias? }) | kernel: 25-element array | Custom 5×5 convolution | | customShader({ source, uniforms? }) | GLSL source + uniforms | User-defined shader |

Custom Shaders

Write GLSL that runs per-pixel. You get these built-in uniforms for free:

  • u_texture — input image (sampler2D)
  • v_texCoord — current pixel's texture coordinate (vec2)
  • u_resolution — image size in pixels (vec2)
  • u_texelSize1.0 / u_resolution (vec2)
const sepia = customShader({
  source: `
    vec4 color = texture2D(u_texture, v_texCoord);
    float grey = dot(color.rgb, vec3(0.299, 0.587, 0.114));
    gl_FragColor = vec4(
      grey + u_tone * 0.2,
      grey + u_tone * 0.05,
      grey - u_tone * 0.15,
      color.a
    );
  `,
  uniforms: { u_tone: 1.0 },
});

License

MIT