Filters and Shaders in PixiJS

Updated June 2026

PixiJS provides a powerful filter system that applies real-time GPU-powered visual effects to any display object. Built-in filters handle common effects like blur, color adjustment, and displacement mapping, while custom shaders written in GLSL or WGSL let you create any visual effect the GPU can compute. Filters transform good-looking games into visually distinctive ones.

How Filters Work in PixiJS

A filter is a GPU shader program that processes pixels after a display object (or container of objects) has been rendered. When you assign a filter to a sprite or container, PixiJS first renders that object to an off-screen framebuffer texture instead of directly to the canvas. The filter shader then processes every pixel of that texture, applying its effect, and outputs the result to the screen or to the next filter in the chain.

This render-to-texture approach means filters can access and modify the complete visual output of their target. A blur filter can sample neighboring pixels because the entire object is available as a texture. A color matrix filter can transform every pixel's color channels. A displacement filter can shift pixel positions based on a separate displacement map texture.

Apply a filter by assigning it to the filters array on any display object: sprite.filters = [new BlurFilter()]. Applying a filter to a Container affects all children of that container, which makes it easy to blur an entire background layer, desaturate all enemies, or add a glow to a group of UI elements with a single filter assignment.

Multiple filters can be chained by adding them to the array: container.filters = [blurFilter, colorFilter]. They execute in order, with each filter processing the output of the previous one. This lets you build complex effect chains from simple building blocks.

Built-in Filters

PixiJS ships with several built-in filters that cover the most common visual effects needed in games and interactive applications.

BlurFilter applies a Gaussian blur with configurable strength on the X and Y axes independently. Low blur values (2-4) create subtle softness for background layers or depth-of-field effects. Higher values (8-16) produce a strong frosted-glass look useful for pause screens or dialog overlays that blur the game behind them. The quality property controls how many passes the blur uses, trading sharpness for performance.

ColorMatrixFilter is the most versatile built-in filter. It transforms pixel colors through a 5x4 matrix, enabling brightness adjustment, contrast enhancement, saturation and desaturation, hue rotation, sepia tone, greyscale conversion, and color channel swapping. Rather than constructing the matrix manually, ColorMatrixFilter provides convenience methods: filter.brightness(1.5), filter.contrast(0.8), filter.saturate(-0.5), filter.hue(90). Combine multiple adjustments by chaining calls.

DisplacementFilter shifts pixel positions based on a displacement map texture, creating effects like water ripples, heat haze, shockwaves, and lens distortion. The red and green channels of the displacement map control horizontal and vertical pixel offset respectively. Animate the displacement map's position to create moving ripple effects, or scale the filter intensity to pulse a shockwave outward from an impact point.

NoiseFilter adds procedural noise to the rendered output, simulating film grain, static, or texture roughness. The noise property controls intensity from 0 (none) to 1 (maximum). The seed property can be changed each frame to animate the noise pattern, or kept constant for a static grain overlay.

AlphaFilter applies a uniform alpha (transparency) to the entire filtered object. While you can set alpha directly on a display object, AlphaFilter is useful when you need to fade a container's visual output uniformly without affecting hit testing or child alpha values independently.

The pixi-filters Collection

Beyond the core built-in filters, the @pixi/filter-* packages (often called pixi-filters) provide dozens of additional effects maintained by the PixiJS community. These include GlowFilter for outer glow effects around sprites, OutlineFilter for colored borders, DropShadowFilter for configurable drop shadows, CRTFilter for retro monitor scanline effects, ShockwaveFilter for animated circular distortions, GodrayFilter for volumetric light beam effects, and many more.

Install individual filter packages from npm as needed: npm install @pixi/filter-glow. Each filter follows the same API pattern as the built-in ones, accepting configuration options in the constructor and assignable to any display object's filters array. The pixi-filters collection is the fastest way to add polished visual effects without writing custom shader code.

Writing Custom Shaders

When built-in and community filters do not provide the exact effect you need, PixiJS v8 lets you write custom shaders in GLSL (for the WebGL renderer) or WGSL (for the WebGPU renderer).

A custom filter consists of a fragment shader that processes each pixel, uniform variables that pass data from JavaScript to the shader (such as time values, colors, or intensity parameters), and optionally a vertex shader if you need to transform geometry. PixiJS's Filter class handles the boilerplate: texture binding, framebuffer management, and uniform uploading. You focus on writing the per-pixel logic.

The fragment shader receives the current pixel's texture coordinates and can sample the input texture (the rendered display object) at any position. This enables effects like sampling neighboring pixels for edge detection, distorting coordinates for warp effects, blending multiple texture samples for motion blur, or computing procedural patterns like fire, water, or energy fields from mathematical functions.

Uniforms are the bridge between your game code and the shader. Define uniforms when creating the filter, then update their values each frame from JavaScript. A common pattern is passing a time uniform that increments every frame, which the shader uses to animate effects. Other useful uniforms include intensity (to fade effects in and out), color (to tint the effect), and resolution (to ensure effects scale correctly across different screen sizes).

For PixiJS v8's WebGPU renderer, shaders are written in WGSL instead of GLSL. WGSL has a different syntax (more similar to Rust than C) but serves the same purpose. If you want your game to work with both WebGL and WebGPU renderers, you can provide both a GLSL and WGSL version of your shader, and PixiJS selects the appropriate one based on the active renderer.

Practical Filter Patterns for Games

Several filter usage patterns appear frequently in 2D games and are worth understanding as ready-to-use techniques.

Damage flash: When a character takes damage, apply a ColorMatrixFilter briefly to tint the sprite red or white. Set the filter, wait 2-3 frames using the ticker, then remove it. This instant visual feedback is standard in action games and requires no additional sprites or textures.

Pause blur: When the player pauses, apply a BlurFilter to the gameplay container and render the pause menu on top. This clearly communicates that the game world is inactive while keeping it visible as context behind the menu. Animate the blur strength from 0 to the target value over a few frames for a smooth transition.

Water surface: Apply a DisplacementFilter to the background or water layer with a tileable noise texture as the displacement map. Animate the displacement map's x and y offset in the ticker to create continuously moving ripple distortion. Combine with a slight blue tint using ColorMatrixFilter for a convincing water surface effect.

Bloom and glow: Use GlowFilter from the pixi-filters package to add an outer glow to magical effects, power-ups, or selected UI elements. The glow color, distance, and strength are all configurable. For a bloom effect on bright areas, render the bright elements to a separate container, apply BlurFilter, and composite them over the main scene with additive blending.

Night mode: Apply a ColorMatrixFilter to the entire stage to reduce brightness, shift colors toward blue, and lower saturation. This transforms a daytime scene into a nighttime version without creating separate art assets. Combine with a spotlight effect using a custom radial gradient shader to simulate a flashlight or torch illuminating a circle around the player.

Performance Considerations

Filters are the most performance-sensitive feature in PixiJS because each filter requires rendering to a framebuffer texture and running a shader program over every pixel. A few guidelines help keep filter usage efficient.

Apply filters to the smallest possible target. Filtering a small sprite is far cheaper than filtering a container that covers the entire screen, because the framebuffer texture is sized to fit the target's bounds. If you need to blur only one character, apply the filter to that character's sprite rather than to a larger container.

Minimize the number of active filters. Each filter in the chain adds another full-screen texture pass. Two or three filters on the same object are usually fine, but stacking ten filters on a container will cause frame rate drops. Combine multiple color adjustments into a single ColorMatrixFilter rather than using separate filters for brightness, contrast, and saturation.

Disable filters when they are not needed. Set sprite.filters = null or set the filter's enabled = false when the effect should not be visible. A disabled filter consumes no rendering time, so toggling filters off when not in use is better than leaving them active at zero intensity.

Test on your target hardware. Desktop GPUs handle filters with ease, but mobile GPUs have less fill rate and may struggle with multiple filtered layers at high resolution. Profile on real devices to find the right balance between visual quality and frame rate.

Key Takeaway

PixiJS filters let you apply real-time visual effects to any display object using the GPU. Use built-in filters for common effects, the pixi-filters community packages for specialized effects, and custom GLSL or WGSL shaders for unique visual styles. Apply filters to the smallest possible target and disable them when not visible to maintain performance.