In this tutorial, you'll learn how to create a mesmerizing animated plasma effect using Ruby2D. This classic demoscene effect uses mathematical functions to generate flowing, colorful patterns that look like liquid plasma.
gem install ruby2d)
A plasma effect is created by combining multiple sine waves that vary over space and time. The result is a smooth, organic-looking animation with flowing colors. It's been a staple of computer graphics demos since the 1990s.
First, we need to require Ruby2D and configure our window:
require 'ruby2d'
set title: "Plasma Effect"
set width: 640
set height: 480
set background: 'black'
This creates a 640x480 window with a black background.
Instead of calculating colors for every pixel (which would be slow), we create a grid of rectangles:
GRID_WIDTH = 80
GRID_HEIGHT = 60
CELL_WIDTH = Window.width / GRID_WIDTH
CELL_HEIGHT = Window.height / GRID_HEIGHT
This divides our window into an 80x60 grid. Each cell will be 8x8 pixels.
Now we create a rectangle for each grid cell:
plasma_grid = []
GRID_HEIGHT.times do |y|
row = []
GRID_WIDTH.times do |x|
rect = Rectangle.new(
x: x * CELL_WIDTH,
y: y * CELL_HEIGHT,
width: CELL_WIDTH,
height: CELL_HEIGHT,
color: 'black'
)
row << rect
end
plasma_grid << row
end
This creates a 2D array where plasma_grid[y][x] gives us the rectangle at position (x, y).
This is where the magic happens! The plasma function combines multiple sine waves:
def plasma_color(x, y, time)
# Four different sine waves
v1 = Math.sin(x * 0.1 + time)
v2 = Math.sin(y * 0.1 + time * 0.8)
v3 = Math.sin((x + y) * 0.08 + time * 0.5)
v4 = Math.sin(Math.sqrt(x * x + y * y) * 0.05 + time)
# Average them together
value = (v1 + v2 + v3 + v4) / 4.0
# ... (color conversion continues)
end
By adding time to each wave with different speeds, they animate at different rates, creating complex patterns.
The sine waves give us values between -1 and 1. We need to convert these to colors:
# Normalize to 0-1 range
hue = (value + 1.0) * 0.5
# Create RGB colors using sine waves offset by 120 degrees
r = (Math.sin(hue * Math::PI * 2) * 0.5 + 0.5)
g = (Math.sin((hue + 0.33) * Math::PI * 2) * 0.5 + 0.5)
b = (Math.sin((hue + 0.66) * Math::PI * 2) * 0.5 + 0.5)
[r, g, b, 1.0] # Return RGBA array
This creates a rainbow gradient by offsetting the red, green, and blue channels.
Finally, we animate by updating colors every frame:
time = 0.0
update do
time += 0.03 # Increment time each frame
GRID_HEIGHT.times do |y|
GRID_WIDTH.times do |x|
color = plasma_color(x, y, time)
plasma_grid[y][x].color = color
end
end
end
show # Start the window
The update block runs every frame (typically 60 times per second), recalculating colors based on the current time.
Think of each sine wave as a ripple in water. When multiple ripples overlap, they create interference patterns. The plasma effect simulates this by combining waves traveling in different directions and at different speeds.
The time variable makes these waves move, while the x and y coordinates determine which part of the wave we're looking at for each grid cell.
time += 0.03 # Slower
time += 0.1 # Faster
time += 0.01 # Very slow, hypnotic
# More waves = more complex patterns
v5 = Math.sin(x * 0.15 - y * 0.15 + time * 1.2)
value = (v1 + v2 + v3 + v4 + v5) / 5.0
# Fire colors (reds and oranges)
r = value + 1.0
g = (value + 1.0) * 0.5
b = 0.0
# Ocean colors (blues and greens)
r = 0.0
g = (value + 1.0) * 0.5
b = value + 1.0
GRID_WIDTH and GRID_HEIGHT for better performanceNow that you understand the basics, try these challenges:
Happy coding! Share your plasma creations! 🎨✨