Introduction
The plasma effect is a classic demoscene effect that creates fluid, colorful animations resembling swirling clouds or flames. In this tutorial, you'll learn how to create this effect from scratch using pure JavaScript and the <canvas> element.
Step 1: HTML Structure
Let's start with a basic HTML structure with a canvas element:
<canvas id="plasmaCanvas" width="400" height="400"></canvas>
Step 2: Canvas Initialization
The first step is to get the 2D canvas context and prepare a pixel buffer:
const canvas = document.getElementById('plasmaCanvas');
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
// Create an ImageData object for pixel manipulation
const imageData = ctx.createImageData(width, height);
const data = imageData.data; // Array of RGBA pixels
data array contains RGBA values for each pixel. Each pixel takes up 4 elements: Red, Green, Blue, Alpha.
Step 3: The Math Behind Plasma
The plasma effect is based on overlapping sinusoidal functions. For each pixel (x, y), we calculate a value using a combination of sin() and cos() functions:
function plasma(x, y, time) {
// Different sine waves with different frequencies
const value =
Math.sin(x / 16.0 + time) +
Math.sin(y / 8.0 + time) +
Math.sin((x + y) / 16.0 + time) +
Math.sin(Math.sqrt(x * x + y * y) / 8.0 + time);
// Normalize the value to range 0-1
return (value + 4) / 8;
}
Each of these sinusoidal functions creates a different pattern:
sin(x / 16.0)- horizontal wavessin(y / 8.0)- vertical wavessin((x + y) / 16.0)- diagonal wavessin(sqrt(x² + y²) / 8.0)- concentric circles
Step 4: Color Mapping
We convert the plasma value (0-1) to RGB colors using sinusoidal functions with phase shifts:
function getColor(value) {
// Use sin() with different shifts for RGB
const r = Math.floor(128 + 128 * Math.sin(value * Math.PI * 2));
const g = Math.floor(128 + 128 * Math.sin(value * Math.PI * 2 + 2));
const b = Math.floor(128 + 128 * Math.sin(value * Math.PI * 2 + 4));
return [r, g, b];
}
Step 5: Rendering
Now let's combine everything into a render function:
function render(time) {
// Convert time to seconds and slow down
time = time / 1000;
// For each pixel
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
// Calculate plasma value
const value = plasma(x, y, time);
// Convert to color
const [r, g, b] = getColor(value);
// Set pixel in buffer
const index = (y * width + x) * 4;
data[index] = r; // Red
data[index + 1] = g; // Green
data[index + 2] = b; // Blue
data[index + 3] = 255; // Alpha (full opacity)
}
}
// Draw buffer to canvas
ctx.putImageData(imageData, 0, 0);
}
Step 6: Animation Loop
The final step is creating an animation loop using requestAnimationFrame:
function animate(time) {
render(time);
requestAnimationFrame(animate);
}
// Start the animation
requestAnimationFrame(animate);
Demo: See the Effect in Action
Complete Code
Here's the complete source code for the plasma effect:
const canvas = document.getElementById('plasmaCanvas');
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
const imageData = ctx.createImageData(width, height);
const data = imageData.data;
function plasma(x, y, time) {
const value =
Math.sin(x / 16.0 + time) +
Math.sin(y / 8.0 + time) +
Math.sin((x + y) / 16.0 + time) +
Math.sin(Math.sqrt(x * x + y * y) / 8.0 + time);
return (value + 4) / 8;
}
function getColor(value) {
const r = Math.floor(128 + 128 * Math.sin(value * Math.PI * 2));
const g = Math.floor(128 + 128 * Math.sin(value * Math.PI * 2 + 2));
const b = Math.floor(128 + 128 * Math.sin(value * Math.PI * 2 + 4));
return [r, g, b];
}
function render(time) {
time = time / 1000;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const value = plasma(x, y, time);
const [r, g, b] = getColor(value);
const index = (y * width + x) * 4;
data[index] = r;
data[index + 1] = g;
data[index + 2] = b;
data[index + 3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
}
function animate(time) {
render(time);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Experiments and Modifications
Now that you have a working plasma effect, you can experiment with different parameters:
1. Change Wave Frequency
Modify the divisor values (16.0, 8.0) in the plasma() function to create larger or smaller patterns.
2. Add More Waves
Add more sinusoidal functions to the sum, for example:
Math.sin(x / 32.0 - time * 0.5)
3. Change Color Scheme
Experiment with different phase shifts or use other functions for color mapping.
4. Change Animation Speed
Multiply time by a factor to speed up or slow down the animation:
time = time / 1000 * 0.5; // Slow down by half
More JavaScript tutorials:
Spinning squares - visual effect (25 lines)
Oldschool fire effect (20 lines)
Fireworks (60 lines)
Animated fractal (32 lines)
Physics engine for beginners