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

@vshaders/dither

v0.2.0

Published

Ordered (Bayer) dithering thresholds and quantizers as pure WGSL modules for vgpu shaders

Readme

@vshaders/dither

Ordered (Bayer) dithering thresholds and quantizers as pure WGSL modules for vgpu shaders:

import { bayer8, ditherQuantize3 } from "@vshaders/dither/ordered";
import { linearToSrgb3 } from "@vgpu/wgsl-std/color";

@fragment fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
  let gradient = vec3f(position.x / 512.0);      // linear-light ramp
  let display = linearToSrgb3(gradient);         // quantize display-referred
  let threshold = bayer8(vec2u(position.xy));
  return vec4f(ditherQuantize3(display, 2.0, threshold), 1.0); // classic 1-bit look
}

Every module is pure WGSL — functions only, no bindings, no entry points — so vgpu's resolver can prune whatever you don't import. Ordered dithering trades color depth for spatial pattern: each pixel compares against a fixed per-pixel threshold, so the average of a dithered region matches the input while individual pixels snap to a small set of levels.

@vshaders/dither/ordered

  • bayer2(coord: vec2u) -> f32, bayer4(coord: vec2u) -> f32, bayer8(coord: vec2u) -> f32 — the normalized ordered-dither threshold in [0, 1) for a pixel coordinate, from the 2×2, 4×4, and 8×8 Bayer matrix respectively. The matrix tiles the plane (only the low bits of coord are read, which is the wrap). Thresholds of the n×n matrix are the permutation of (index + 0.5) / n², so they average exactly 0.5 and never hit 0 or 1 — larger matrices give more intermediate shades before banding.
  • ditherQuantize(value: f32, levels: f32, threshold: f32) -> f32 — quantize value to levels evenly spaced levels over [0, 1], with threshold (from a bayer* function) deciding which neighbor a value between two levels snaps to. levels = 2.0 is the 1-bit look. levels <= 1 returns the value unquantized instead of dividing by zero; values outside [0, 1] quantize onto the extended grid, unclamped.
  • ditherQuantize3(color: vec3f, levels: f32, threshold: f32) -> vec3f — component-wise ditherQuantize with a shared threshold; levels counts levels per channel.

Linear vs display

Dithering happens in whatever space you quantize in. A dithered region reads as the average of its pixels — in the space you quantized. Quantizing linear-light values makes mid-gradients come out visibly too bright once encoded, so for a correct look convert to display-referred first (linearToSrgb3 from @vgpu/wgsl-std/color) and dither that, as in the example above. Quantize linear light only when the quantized values feed further linear-light math instead of the screen.

Provenance

The threshold matrices are B. E. Bayer's ordered-dither index matrices ("An optimum method for two-level rendition of continuous-tone pictures", 1973); the recursive construction that generates them is textbook. This package computes indices with that bit-interleaving construction rather than storing literal matrices. All WGSL here is an original implementation, with edge-case guards (levels <= 1) in the argument ranges the math leaves undefined.

Verifying

npx vgpu check path/to/your-entry-shader.wgsl

resolves the import graph, validates the composed shader, and prints its reflection.

License

MIT