Filters apply post-processing effects to any display object and its children. Use them for blurring, color adjustments, noise, displacement, or custom shader-based effects.
import { Assets, Sprite, BlurFilter, NoiseFilter } from 'pixi.js';
const texture = await Assets.load('photo.png');
const sprite = new Sprite(texture);
// Single filter
sprite.filters = new BlurFilter({ strength: 8 });
// Multiple filters (applied in sequence)
sprite.filters = [
new BlurFilter({ strength: 8 }),
new NoiseFilter({ noise: 0.5 }),
];
Filter order matters. They're applied in array order, so each filter processes the output of the previous one.
PixiJS ships with five built-in filters:
| Filter | Purpose |
|---|---|
| AlphaFilter | Applies uniform transparency |
| BlurFilter | Gaussian blur |
| ColorMatrixFilter | Color transformations via a 5x4 matrix |
| DisplacementFilter | Distorts using a displacement map texture |
| NoiseFilter | Adds random noise for a grainy look |
import { AlphaFilter } from 'pixi.js';
sprite.filters = new AlphaFilter({ alpha: 0.5 });
import { BlurFilter } from 'pixi.js';
sprite.filters = new BlurFilter({
strength: 8, // blur intensity (default: 8)
quality: 4, // number of blur passes (default: 4)
kernelSize: 5, // kernel size (default: 5)
});
You can also blur on a single axis with strengthX / strengthY.
import { ColorMatrixFilter } from 'pixi.js';
const colorMatrix = new ColorMatrixFilter();
colorMatrix.brightness(0.5, false);
colorMatrix.contrast(0.8, false);
colorMatrix.saturate(1.2, true); // true = multiply with current matrix
sprite.filters = colorMatrix;
Available presets: brightness, contrast, saturate, desaturate, greyscale, blackAndWhite, hue, negative, sepia, technicolor, polaroid, toBGR, kodachrome, browni, vintage, colorTone, night, predator, lsd, reset.
import { Sprite, DisplacementFilter } from 'pixi.js';
const displacementSprite = Sprite.from('displacement-map.png');
sprite.filters = new DisplacementFilter({
sprite: displacementSprite,
scale: 20,
});
import { NoiseFilter } from 'pixi.js';
sprite.filters = new NoiseFilter({
noise: 0.5, // noise intensity (default: 0.5)
seed: Math.random(), // random seed (default: Math.random())
});
PixiJS provides advanced blend modes through a separate import. These register as blend modes on containers, not as filters you apply directly.
import 'pixi.js/advanced-blend-modes';
sprite.blendMode = 'color-burn';
Available blend modes after importing:
| Blend mode string | Class |
|---|---|
'color' |
ColorBlend |
'color-burn' |
ColorBurnBlend |
'color-dodge' |
ColorDodgeBlend |
'darken' |
DarkenBlend |
'difference' |
DifferenceBlend |
'divide' |
DivideBlend |
'exclusion' |
ExclusionBlend |
'hard-light' |
HardLightBlend |
'hard-mix' |
HardMixBlend |
'lighten' |
LightenBlend |
'linear-burn' |
LinearBurnBlend |
'linear-dodge' |
LinearDodgeBlend |
'linear-light' |
LinearLightBlend |
'luminosity' |
LuminosityBlend |
'negation' |
NegationBlend |
'overlay' |
OverlayBlend |
'pin-light' |
PinLightBlend |
'saturation' |
SaturationBlend |
'soft-light' |
SoftLightBlend |
'subtract' |
SubtractBlend |
'vivid-light' |
VividLightBlend |
Create custom filters with GLSL shaders. PixiJS v8 uses GLSL ES 3.0 style (in/out instead of attribute/varying, texture() instead of texture2D).
Filter.from()The simplest way to create a custom filter. You usually only need a fragment shader; PixiJS provides a default vertex shader that handles positioning. Pass undefined for the vertex to use the default:
const simpleFilter = Filter.from({
gl: {
fragment: `
in vec2 vTextureCoord;
out vec4 finalColor;
uniform sampler2D uTexture;
void main(void) {
vec4 color = texture(uTexture, vTextureCoord);
finalColor = vec4(1.0 - color.rgb, color.a); // invert colors
}
`,
},
resources: {},
});
For full control over both vertex and fragment shaders:
import { Filter } from 'pixi.js';
const waveFilter = Filter.from({
gl: {
vertex: `
in vec2 aPosition;
out vec2 vTextureCoord;
uniform vec4 uInputSize;
uniform vec4 uOutputFrame;
uniform vec4 uOutputTexture;
vec4 filterVertexPosition(void)
{
vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;
position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;
position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;
return vec4(position, 0.0, 1.0);
}
vec2 filterTextureCoord(void)
{
return aPosition * (uOutputFrame.zw * uInputSize.zw);
}
void main(void)
{
gl_Position = filterVertexPosition();
vTextureCoord = filterTextureCoord();
}
`,
fragment: `
in vec2 vTextureCoord;
out vec4 finalColor;
uniform sampler2D uTexture;
uniform float uWaveAmplitude;
uniform float uWaveFrequency;
uniform float uTime;
void main(void)
{
vec2 coord = vTextureCoord;
coord.x += sin(coord.y * uWaveFrequency + uTime) * uWaveAmplitude;
finalColor = texture(uTexture, coord);
}
`,
},
resources: {
waveUniforms: {
uWaveAmplitude: { value: 0.05, type: 'f32' },
uWaveFrequency: { value: 10.0, type: 'f32' },
uTime: { value: 0.0, type: 'f32' },
},
},
});
sprite.filters = [waveFilter];
app.ticker.add((ticker) => {
waveFilter.resources.waveUniforms.uniforms.uTime += 0.1 * ticker.deltaTime;
});
new Filter() with pre-built programsFor more control, construct GlProgram and GpuProgram objects yourself:
import { Filter, GlProgram } from 'pixi.js';
const glProgram = new GlProgram({ vertex: vertexSrc, fragment: fragmentSrc });
const filter = new Filter({
glProgram,
resources: {
timeUniforms: {
uTime: { value: 0.0, type: 'f32' },
},
},
});
out vec4 finalColor; in fragment shaders (not gl_FragColor)texture() to sample textures (not texture2D)filterVertexPosition() and filterTextureCoord() helpers to handle output frame positioningresources are accessible at filter.resources.<groupName>.uniforms.<uniformName>
For dual-renderer support (WebGL + WebGPU), include both a glProgram and a gpuProgram.
All filters accept these base options:
| Option | Type | Default | Description |
|---|---|---|---|
blendMode |
string |
'normal' |
Blend mode for filter output |
resolution |
number | 'inherit' |
1 |
Render resolution |
padding |
number |
0 |
Extra pixels around the filter area |
antialias |
FilterAntialias | boolean |
'off' |
Anti-aliasing mode |
blendRequired |
boolean |
false |
Whether blending with background is needed |
clipToViewport |
boolean |
true |
Clip filter to viewport bounds |
sprite.filterArea to a fixed Rectangle to skip this calculation and reduce the processed region.sprite.filters = null to skip filter processing entirelyquality on BlurFilter reduces passesimport { Rectangle, BlurFilter } from 'pixi.js';
// Constrain filter processing to a 200x200 area
sprite.filterArea = new Rectangle(0, 0, 200, 200);
// Share a single blur across multiple sprites
const sharedBlur = new BlurFilter({ strength: 4 });
sprite1.filters = [sharedBlur];
sprite2.filters = [sharedBlur];