| name | filters-and-postfx |
| description | Use this skill when applying visual filters or post-processing effects in Phaser 4. Covers bloom, blur, glow, color matrix, barrel distortion, displacement, custom shaders, and the filter pipeline. Triggers on: filter, post-processing, shader, bloom, blur, glow, color effects. |
Phaser 4 Filters and Post-FX
Quick Start
Add a glow effect to a sprite:
const sprite = this.add.sprite(400, 300, 'player');
sprite.enableFilters();
sprite.filters.internal.addGlow(0xff00ff, 4, 0, 1);
Add a blur to the camera:
const camera = this.cameras.main;
camera.filters.internal.addBlur(0, 2, 2, 1);
Core Concepts
How Filters Work in v4
Filters are GPU-based post-processing effects applied after an object or camera renders to a texture. Each filter runs a shader pass over that texture, producing the final visual output. Filters are WebGL only.
The rendering pipeline for a camera with filters:
- Objects render to a texture the size of the camera.
- Internal filters process that texture, applying effects in object/camera local space.
- The texture is drawn to a context-sized texture, applying camera transformations (position, rotation, zoom).
- External filters process that context texture, applying effects in screen space.
- The final texture is composited into the output.
Internal vs External Filters
Every FilterList exposes two sub-lists: filters.internal and filters.external. The distinction controls when the filter runs relative to the camera/object transform:
- Internal -- applied before the camera transform. Effects operate in the object's local coordinate space. A horizontal blur on a rotated object appears rotated with the object. Internal filters only cover the object/camera region, so they are cheaper.
- External -- applied after the camera transform. Effects operate in screen space. A horizontal blur on a rotated object always blurs horizontally on screen. External filters are full-screen and more expensive.
Use internal filters wherever possible for better performance.
FilterList
FilterList (Phaser.GameObjects.Components.FilterList) is the container that holds filter controllers. It provides:
add(filter, index) -- add a Controller instance at an optional index
remove(filter, forceDestroy) -- remove and destroy a filter
clear() -- remove and destroy all filters
getActive() -- return all filters where active === true
list -- the raw array of Controllers (safe to reorder)
- Convenience factory methods:
addBlur(), addGlow(), addMask(), etc.
Filter Controllers
Every filter is a Phaser.Filters.Controller subclass. Common Controller properties:
| Property | Type | Description |
|---|
active | boolean | Toggle the filter on/off without removing it |
camera | Camera | The camera that owns this filter |
renderNode | string | The render node ID for the shader |
paddingOverride | Rectangle | Override automatic padding calculation |
ignoreDestroy | boolean | If true, the filter survives when its FilterList is destroyed (for reuse) |
Key methods: setActive(bool), setPaddingOverride(left, top, right, bottom), getPadding(), destroy().
Enabling Filters on Game Objects
Cameras have filters available by default. Game objects do not -- you must call enableFilters() first:
const sprite = this.add.sprite(400, 300, 'hero');
sprite.enableFilters();
sprite.filters.internal.addGlow();
sprite.filters.external.addVignette();
enableFilters() creates an internal filterCamera on the game object that handles rendering the object to a texture for filter processing. It returns this for chaining.
Related properties on game objects after enabling:
| Property | Default | Description |
|---|
filterCamera | null -> Camera | The internal camera used for filter rendering |
filters | null -> {internal, external} | Access to the FilterList pair |
renderFilters | true | Master toggle for all filter rendering |
filtersAutoFocus | true | Auto-adjust camera to follow the object |
filtersFocusContext | false | Focus on the rendering context instead of the object bounds |
filtersForceComposite | false | Always draw to a framebuffer even with no active filters |
maxFilterSize | null -> Vector2 | Maximum texture size for filter framebuffers |
Use willRenderFilters() to check if any active filters will actually render.
Common Patterns
Adding Filters to Game Objects
const sprite = this.add.sprite(400, 300, 'enemy');
sprite.enableFilters();
const glow = sprite.filters.internal.addGlow(0x00ff00, 4);
glow.outerStrength = 8;
glow.color = 0xff0000;
glow.setActive(false);
sprite.filters.internal.remove(glow);
Camera Filters
const camera = this.cameras.main;
const blur = camera.filters.internal.addBlur(0, 2, 2, 1);
const vignette = camera.filters.external.addVignette(0.5, 0.5, 0.5, 0.5);
const cm = camera.filters.internal.addColorMatrix();
cm.colorMatrix.sepia();
Chaining Multiple Filters
Filters execute in list order. Each filter receives the output of the previous one:
const cam = this.cameras.main;
const cm = cam.filters.internal.addColorMatrix();
cm.colorMatrix.brightness(0.2);
cam.filters.internal.addBlur(1, 2, 2, 1);
cam.filters.external.addVignette(0.5, 0.5, 0.5, 0.8);
Masks via Filters
Masks in v4 are implemented as filters. They use the alpha channel of a texture or game object to control visibility:
sprite.enableFilters();
sprite.filters.internal.addMask('maskTexture');
const maskShape = this.add.circle(0, 0, 100, 0xffffff);
sprite.enableFilters();
const mask = sprite.filters.internal.addMask(maskShape);
mask.invert = true;
mask.autoUpdate = true;
mask.needsUpdate = true;
sprite.filters.external.addMask(maskShape, false, this.cameras.main);
Internal masks match the object being filtered. External masks match the camera context. Use a viewCamera parameter to control which camera renders the mask game object.
Wipe / Reveal Transitions
const camera = this.cameras.main;
const wipe = camera.filters.external.addWipe(0.1, 0, 0);
this.tweens.add({
targets: wipe,
progress: 1,
duration: 2000,
ease: 'Linear'
});
wipe.setLeftToRight();
wipe.setTopToBottom();
wipe.setRevealEffect();
wipe.setWipeEffect();
wipe.setTexture('nextSceneCapture');
ParallelFilters (Custom Bloom and Compositing)
ParallelFilters splits the input into two paths, processes each independently, then blends the results. This replaces the dedicated Bloom filter from v3:
const camera = this.cameras.main;
const pf = camera.filters.internal.addParallelFilters();
pf.top.addThreshold(0.5, 1);
pf.top.addBlur();
pf.blend.blendMode = Phaser.BlendModes.ADD;
pf.blend.amount = 0.5;
CaptureFrame for Scene-Level Effects
CaptureFrame captures the current render state at the point it appears in the display list. Objects rendered before it are captured; objects after it are not:
this.cameras.main.setForceComposite(true);
const bg = this.add.image(400, 300, 'background');
const capture = this.add.captureFrame('myCapture');
const display = this.add.image(400, 300, 'myCapture');
display.enableFilters();
display.filters.internal.addBlur(0, 4, 4, 2);
All Built-in Filters
| Filter | Add Method | Description |
|---|
| Barrel | addBarrel(amount) | Pinch/expand distortion. amount=1 is neutral. |
| Blend | addBlend(texture, blendMode, amount, color) | Blend another texture using a blend mode. Supports modes not available in standard WebGL. |
| Blocky | addBlocky(config) | Pixelation that preserves original colors (no blending). Best without anti-aliasing. |
| Blur | addBlur(quality, x, y, strength, color, steps) | Gaussian blur. Quality: 0=low, 1=medium, 2=high. |
| Bokeh | addBokeh(radius, amount, contrast) | Depth-of-field bokeh blur effect. |
| ColorMatrix | addColorMatrix() | Color manipulation via matrix. Access .colorMatrix for sepia, grayscale, brightness, hue, etc. |
| CombineColorMatrix | addCombineColorMatrix(texture) | Combine channels from two textures via color matrices. Useful for alpha transfer. |
| Displacement | addDisplacement(texture, x, y) | Pixel displacement using a displacement map texture. Values are very small floats (e.g. 0.005). |
| Glow | addGlow(color, outerStrength, innerStrength, scale, knockout, quality, distance) | Luminous halo around edges. Supports inner/outer glow and knockout mode. |
| GradientMap | addGradientMap(config) | Recolor image using a ColorRamp based on brightness. |
| ImageLight | addImageLight(config) | Image-based lighting using a panorama environment map and normal map. |
| Key | addKey(config) | Chroma key: remove or isolate a specific color. Config: { color, threshold, feather, isolate }. |
| Mask | addMask(mask, invert, viewCamera, viewTransform, scaleFactor) | Alpha masking via texture or game object. |
| NormalTools | addNormalTools(config) | Manipulate normal maps: rotate, adjust facing power, output grayscale facing data. |
| PanoramaBlur | addPanoramaBlur(config) | Spherically-correct blur for panorama images. For use with ImageLight. Very slow. |
| ParallelFilters | addParallelFilters() | Split input into two filter paths, blend results. Use for custom bloom. |
| Pixelate | addPixelate(amount) | Mosaic/pixelation effect. Pixel size = 2 + amount. Blends colors (unlike Blocky). |
| Quantize | addQuantize(config) | Reduce color palette. Supports RGBA/HSVA modes, gamma, offset, dithering. |
| Sampler | addSampler(callback, region) | Extract pixel data from the render. Does not alter the image. Expensive. |
| Shadow | addShadow(x, y, decay, power, color, samples, intensity) | Drop shadow with offset, decay, and color. |
| Threshold | addThreshold(edge1, edge2, invert) | Binary threshold per channel. Edges can be arrays for per-channel control. |
| TiltShift | addTiltShift(radius, amount, contrast, blurX, blurY, strength) | Miniature/tilt-shift effect (uses Bokeh internally). |
| Vignette | addVignette(x, y, radius, strength, color, blendMode) | Edge darkening/coloring. Supports NORMAL, ADD, MULTIPLY, SCREEN blend modes. |
| Wipe | addWipe(wipeWidth, direction, axis, reveal, wipeTexture) | Wipe/reveal transition. Animate progress via tween. |
API Quick Reference
Enabling and Accessing Filters
gameObject.enableFilters();
gameObject.filters.internal.addBlur();
gameObject.filters.external.addGlow();
camera.filters.internal.addBlur();
camera.filters.external.addGlow();
FilterList Methods
const list = camera.filters.internal;
list.addBlur();
list.add(controllerInstance);
list.add(controller, 2);
list.remove(controller);
list.clear();
list.getActive();
list.list;
Controller Common API
controller.active = false;
controller.setActive(true);
controller.setPaddingOverride(10, 10, 10, 10);
controller.setPaddingOverride(null);
controller.ignoreDestroy = true;
controller.destroy();
Mask Filter API
const mask = list.addMask('texKey');
const mask = list.addMask(gameObject);
mask.invert = true;
mask.autoUpdate = false;
mask.needsUpdate = true;
mask.setTexture('newKey');
mask.setGameObject(newGO);
mask.viewCamera = otherCamera;
mask.viewTransform = 'local';
mask.scaleFactor = 0.5;
ColorMatrix Presets
const cm = list.addColorMatrix();
cm.colorMatrix.sepia();
cm.colorMatrix.grayscale(1);
cm.colorMatrix.brightness(0.3);
cm.colorMatrix.hue(90);
cm.colorMatrix.saturate(-0.5);
cm.colorMatrix.contrast(0.3);
cm.colorMatrix.blackWhite();
cm.colorMatrix.negative();
cm.colorMatrix.desaturate();
cm.colorMatrix.night(0.5);
cm.colorMatrix.lsd();
cm.colorMatrix.brown();
cm.colorMatrix.vintagePinhole();
cm.colorMatrix.kodachrome();
cm.colorMatrix.technicolor();
cm.colorMatrix.polaroid();
cm.colorMatrix.shiftToBGR();
Gotchas
-
WebGL only -- Filters do not work in Canvas renderer. enableFilters() returns early if WebGL is not available.
-
enableFilters() required for game objects -- Cameras have filters by default. Sprites, images, containers, and other game objects require enableFilters() before accessing filters.
-
Performance cost -- Each object with active filters creates extra draw calls (one for the base render plus one per active filter). Use sparingly and performance test early.
-
Internal vs external matters -- Internal filters are cheaper (object-region sized). External filters are full-screen. A blur that should rotate with the object must be internal; a blur that should stay screen-aligned must be external.
-
Filter order matters -- Filters are applied sequentially in list order. The output of one feeds into the next.
-
Glow quality and distance are immutable -- quality and distance on the Glow filter cannot be changed after creation. Destroy and recreate the filter to change them.
-
CaptureFrame requires forceComposite -- The camera must have setForceComposite(true) or otherwise render into a framebuffer for CaptureFrame to work.
-
Padding for expanding effects -- Filters like Blur, Glow, and Shadow can automatically calculate padding to expand the render texture. Override with setPaddingOverride() if needed. Pass null to clear the override. When used on a camera, use camera.getPaddingWrapper(x) to render more world outside the image edge.
-
Controller reuse -- By default, controllers are destroyed when their FilterList is destroyed. Set ignoreDestroy = true to reuse a controller across multiple objects, but you must manage its lifecycle manually. Works best with external filters.
-
Mask game object rendering -- When using a game object as a mask source, it is rendered to a DynamicTexture each frame (if autoUpdate is true). Set autoUpdate = false and use needsUpdate = true for one-shot updates to improve performance for static masks.
-
No Bloom filter -- v4 does not have a dedicated Bloom filter. Use ParallelFilters with Threshold + Blur + ADD blend instead (see Common Patterns), or use Phaser.Actions.AddEffectBloom to automate the process.
v4 Changes from v3
| v3 (FX) | v4 (Filters) | Notes |
|---|
gameObject.preFX / gameObject.postFX | gameObject.filters.internal / gameObject.filters.external | preFX/postFX replaced by internal/external filter lists |
camera.postFX | camera.filters.internal / camera.filters.external | Cameras now have both internal and external lists |
FX.addBloom() | Use ParallelFilters + Threshold + Blur | No dedicated Bloom filter; build it with ParallelFilters or Phaser.Actions.AddEffectBloom |
FX.addCircle() | Use Vignette or Mask | Circle effect removed; use Vignette with radius or a circular Mask, or automate with Phaser.Actions.AddMaskShape |
FX.addGradient() | Use Gradient GameObject + Quantize | New Gradient GameObject renders gradients; Quantize adds steps if wanted |
Glow quality was 0-1 fraction | Glow quality is an integer (default 10) | Stochastic sampling replaces line sampling; higher quality at lower values |
camera.setMask() | camera.filters.internal.addMask() | Masks are now filters, not a separate system |
gameObject.setMask() | gameObject.filters.internal.addMask() | Same unified filter system |
| FX controllers | Phaser.Filters.Controller subclasses | Same pattern: returned controller objects with mutable properties |
| -- | enableFilters() required for game objects | New explicit opt-in step for game objects |
| -- | Blocky, Quantize, Key, Blend, CombineColorMatrix, ImageLight, NormalTools, PanoramaBlur, ParallelFilters, Sampler | New filters added in v4 |
Source File Map
| File | Description |
|---|
src/gameobjects/components/Filters.js | Mixin that adds enableFilters(), filterCamera, filters to game objects |
src/gameobjects/components/FilterList.js | FilterList class with all add*() factory methods |
src/filters/Controller.js | Base Controller class for all filters |
src/filters/Barrel.js | Barrel distortion filter |
src/filters/Blend.js | Texture blend filter |
src/filters/Blocky.js | Color-preserving pixelation filter |
src/filters/Blur.js | Gaussian blur filter |
src/filters/Bokeh.js | Bokeh / tilt shift filter |
src/filters/ColorMatrix.js | Color matrix filter (sepia, grayscale, etc.) |
src/filters/CombineColorMatrix.js | Dual-texture channel combining filter |
src/filters/Displacement.js | Displacement map filter |
src/filters/Glow.js | Glow/outline filter |
src/filters/GradientMap.js | Gradient map recoloring filter |
src/filters/ImageLight.js | Image-based lighting filter |
src/filters/Key.js | Chroma key filter |
src/filters/Mask.js | Alpha mask filter (texture or game object) |
src/filters/NormalTools.js | Normal map manipulation filter |
src/filters/PanoramaBlur.js | Spherical panorama blur filter |
src/filters/ParallelFilters.js | Parallel filter paths with blend |
src/filters/Pixelate.js | Pixelation filter |
src/filters/Quantize.js | Color quantization filter |
src/filters/Sampler.js | Pixel sampling/readback filter |
src/filters/Shadow.js | Drop shadow filter |
src/filters/Threshold.js | Threshold filter |
src/filters/Vignette.js | Vignette filter |
src/filters/Wipe.js | Wipe/reveal transition filter |
src/gameobjects/captureframe/CaptureFrame.js | CaptureFrame game object for scene-level capture |
Related: sprites-and-images.md, cameras.md, v4-new-features.md