Canvas Compositing
Learn how globalAlpha and globalCompositeOperation control transparency and how new pixels blend with everything already drawn on the canvas.
Fading Layers with globalAlpha
ctx.globalAlpha sets a transparency multiplier from 0 (invisible) to 1 (fully opaque) that applies to every drawing operation — fills, strokes, images, gradients — until you change it again. It multiplies with any alpha already present in the fill color or image itself, so a globalAlpha of 0.5 applied to a color that's already 50% transparent results in 25% final opacity.
Example 1: Layered Translucent Panels
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="350" height="230" style="border:1px solid #ccc;"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.globalAlpha = 1;
ctx.fillStyle = '#1e293b';
ctx.fillRect(0, 0, canvas.width, canvas.height); // opaque background
ctx.globalAlpha = 0.5;
ctx.fillStyle = '#38bdf8';
ctx.fillRect(40, 40, 200, 120); // 50% see-through panel
ctx.globalAlpha = 0.5;
ctx.fillStyle = '#f472b6';
ctx.fillRect(140, 100, 200, 120); // overlaps the first panel
ctx.globalAlpha = 1; // always reset when you're done
</script>
</body>
</html>Blending Pixels with globalCompositeOperation
Every draw call combines new pixels with whatever is already on the canvas using a blend rule called the composite operation. The default, 'source-over', simply paints new pixels on top wherever they're opaque. Changing globalCompositeOperation before a draw call changes that rule entirely — some operations mask existing content using the new shape, some punch holes, and some mix colors together like a Photoshop blend mode.
Example 2: Revealing a Photo Through a Shape (destination-in)
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="260" height="260" style="border:1px solid #ccc;"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const photo = new Image();
photo.src = 'assets/photo.jpg';
photo.onload = () => {
ctx.drawImage(photo, 0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'destination-in';
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, 100, 0, Math.PI * 2);
ctx.fill(); // only the circular overlap between photo and circle survives
ctx.globalCompositeOperation = 'source-over'; // reset for whatever draws next
};
</script>
</body>
</html>Common Blend Recipes
- Spotlight/reveal effects: draw the full scene, then mask it down with 'destination-in' and a shape or gradient
- Punching transparent holes: 'destination-out' with a soft radial gradient for vignettes and fades
- Additive glow and particles: 'lighter' so overlapping bright spots accumulate into a hotspot
- Tinting or shadowing artwork: 'multiply' with a translucent color fill on top
- Colored highlight overlays on photos: 'overlay' or 'screen' for punchy, non-flat lighting
Example 3: Additive Glow Particles
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="260" style="border:1px solid #ccc;"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const particles = [
{ x: 80, y: 100, radius: 40 },
{ x: 160, y: 140, radius: 55 },
{ x: 230, y: 90, radius: 35 },
{ x: 190, y: 190, radius: 45 }
];
ctx.fillStyle = '#0f172a';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'lighter';
particles.forEach((p) => {
const glow = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, p.radius);
glow.addColorStop(0, 'rgba(96, 165, 250, 0.8)');
glow.addColorStop(1, 'rgba(96, 165, 250, 0)');
ctx.fillStyle = glow;
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.fill();
});
ctx.globalCompositeOperation = 'source-over';
</script>
</body>
</html>Exercise: Canvas Compositing
What does the globalCompositeOperation property control?