Skip to content

ditherBlueNoise() ​

ts
function ditherBlueNoise(params?: {
  size?: number;
  color?: boolean;
  levels?: number;
}): EffectPass<
  {
    uTexture: (
      __namedParameters: Readonly<EffectUniformContext>,
    ) => WebGLTexture;
    uResolution: (
      __namedParameters: Readonly<EffectUniformContext>,
    ) => [number, number];
    uDpr: (__namedParameters: Readonly<EffectUniformContext>) => number;
    uSize: number;
    uColor: boolean;
    uLevels: number;
  } & {
    uBlueNoise: DataTextureParams;
  }
>;

Creates a blue-noise dithering post-processing effect.

The threshold comes from a 32x32 void-and-cluster blue-noise mask sampled one texel per dither cell. Blue noise has no visible cross-hatch, so it breaks banding more smoothly than any ordered matrix.

Parameters ​

params? ​

Dither configuration.

size? ​

number

Size of each dither cell in CSS pixels, rounded to whole device pixels. The value is independent of the device pixel ratio, so the result looks the same on any display.

You can dynamically update the value:

  • ditherEffect.uniforms.uSize = 3; // chunkier pattern

Default

ts
1 (except for halftone, which uses 4)

color? ​

boolean

When true each channel is dithered on its own, so the palette has levels³ colors. When false the output is grayscale.

You can dynamically update the value:

  • ditherEffect.uniforms.uColor = false;

Default

ts
true;

levels? ​

number

Number of values per channel in the palette (at least 2), evenly spaced in sRGB. In grayscale this is the number of grays; in color it is the number of values per channel, so 3 gives 27 colors. 2 gives pure black and white (or the 8 corners of the RGB cube in color).

You can dynamically update the value:

  • ditherEffect.uniforms.uLevels = 4;

Default

ts
3;

Returns ​

EffectPass<{ uTexture: (__namedParameters: Readonly<EffectUniformContext>) => WebGLTexture; uResolution: (__namedParameters: Readonly<EffectUniformContext>) => [number, number]; uDpr: (__namedParameters: Readonly<EffectUniformContext>) => number; uSize: number; uColor: boolean; uLevels: number; } & { uBlueNoise: DataTextureParams; }>

Remarks ​

Expects linear input and writes sRGB-encoded output, so use it as the last effect, after a tone mapping with outputColorSpace: "linear". The pattern is mixed in linear light between the two nearest palette levels, so the average light matches the source.

Released under the MIT License.