filters-and-postfx
Phaser 4 Filters and Post-FX
Quick Start
Add a glow effect to a sprite:
// In your Scene's create() method:
const sprite = this.add.sprite(400, 300, 'player');
// Step 1: Enable the filter system on the game object (WebGL only)
sprite.enableFilters();
// Step 2: Add filters via .filters.internal or .filters.external
sprite.filters.internal.addGlow(0xff00ff, 4, 0, 1);
Add a blur to the camera:
// Cameras have filters enabled by default - no enableFilters() needed
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 indexremove(filter, forceDestroy)-- remove and destroy a filterclear()-- remove and destroy all filtersgetActive()-- return all filters whereactive === truelist-- 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();
// Now sprite.filters is available
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();
// Add a glow
const glow = sprite.filters.internal.addGlow(0x00ff00, 4);
// Modify at runtime
glow.outerStrength = 8;
glow.color = 0xff0000;
// Temporarily disable
glow.setActive(false);
// Remove and destroy
sprite.filters.internal.remove(glow);
Camera Filters
const camera = this.cameras.main;
// Internal: effect in camera-local space
const blur = camera.filters.internal.addBlur(0, 2, 2, 1);
// External: effect in screen space
const vignette = camera.filters.external.addVignette(0.5, 0.5, 0.5, 0.5);
// Color grading via ColorMatrix
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;
// First: apply color grading
const cm = cam.filters.internal.addColorMatrix();
cm.colorMatrix.brightness(0.2);
// Second: apply blur to the color-graded result
cam.filters.internal.addBlur(1, 2, 2, 1);
// Third: add a vignette on top
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:
// Mask with a static texture
sprite.enableFilters();
sprite.filters.internal.addMask('maskTexture');
// Mask with a game object (renders to DynamicTexture automatically)
const maskShape = this.add.circle(0, 0, 100, 0xffffff);
sprite.enableFilters();
const mask = sprite.filters.internal.addMask(maskShape);
// Invert the mask
mask.invert = true;
// Control auto-updating for game object masks
mask.autoUpdate = true; // default: re-renders each frame
mask.needsUpdate = true; // force a one-time update
// Use a specific camera for viewing the mask object
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);
// Animate via tween
this.tweens.add({
targets: wipe,
progress: 1,
duration: 2000,
ease: 'Linear'
});
// Direction helpers
wipe.setLeftToRight();
wipe.setTopToBottom();
wipe.setRevealEffect(); // reveal mode
wipe.setWipeEffect(); // wipe mode
// Wipe to another texture (for scene transitions)
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();
// Top path: threshold bright areas, then blur them
pf.top.addThreshold(0.5, 1);
pf.top.addBlur();
// Configure the blend (how top combines onto bottom)
pf.blend.blendMode = Phaser.BlendModes.ADD;
pf.blend.amount = 0.5;
// Bottom path: left empty = uses original input
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:
// Requires composite mode on the camera
this.cameras.main.setForceComposite(true);
// Objects rendered before CaptureFrame are captured
const bg = this.add.image(400, 300, 'background');
// Create the capture point
const capture = this.add.captureFrame('myCapture');
// Display the captured texture with filters applied
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
// Game objects: must enable first
gameObject.enableFilters();
gameObject.filters.internal.addBlur();
gameObject.filters.external.addGlow();
// Cameras: filters available immediately
camera.filters.internal.addBlur();
camera.filters.external.addGlow();
FilterList Methods
const list = camera.filters.internal;
list.addBlur(); // Factory method (one per filter type)
list.add(controllerInstance); // Add a pre-built controller
list.add(controller, 2); // Insert at index 2
list.remove(controller); // Remove and destroy
list.clear(); // Remove and destroy all
list.getActive(); // Get all active controllers
list.list; // Raw array (reorder safely)
Controller Common API
controller.active = false; // Disable without removing
controller.setActive(true); // Enable (returns this)
controller.setPaddingOverride(10, 10, 10, 10); // Override padding
controller.setPaddingOverride(null); // Clear override
controller.ignoreDestroy = true; // Survive FilterList.destroy()
controller.destroy(); // Manual cleanup
Mask Filter API
const mask = list.addMask('texKey'); // From texture key
const mask = list.addMask(gameObject); // From game object
mask.invert = true; // Invert mask
mask.autoUpdate = false; // Stop auto-updating GO masks
mask.needsUpdate = true; // Force one update
mask.setTexture('newKey'); // Change texture source
mask.setGameObject(newGO); // Change GO source
mask.viewCamera = otherCamera; // Camera for GO rendering
mask.viewTransform = 'local'; // 'local' or 'world'
mask.scaleFactor = 0.5; // Scale mask texture size
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 accessingfilters. -
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 --
qualityanddistanceon 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. Passnullto clear the override. When used on a camera, usecamera.getPaddingWrapper(x)to render more world outside the image edge. -
Controller reuse -- By default, controllers are destroyed when their FilterList is destroyed. Set
ignoreDestroy = trueto 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
autoUpdateis true). SetautoUpdate = falseand useneedsUpdate = truefor 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.AddEffectBloomto 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