AI Ocean Waves - Calming Meditation

This sketch creates a calming ocean wave animation with layered sine waves in multiple shades of blue. Three waves move at different speeds and amplitudes, creating a sense of depth and peaceful motion. A gradient background transitions from light sky blue to deep ocean blue, and the canvas automatically resizes with the window.

๐ŸŽ“ Concepts You'll Learn

Animation loopSine wavesCanvas gradientsLayered graphicsVertex shapesResponsive canvasTrigonometric functionsColor and transparency

๐Ÿ”„ Code Flow

Code flow showing setup, draw, wave, windowresized

๐Ÿ’ก Click on function names in the diagram to jump to their code

graph TD start[Start] --> setup[setup] setup --> draw[draw loop] draw --> gradient-setup[gradient-setup] draw --> gradient-apply[gradient-apply] draw --> time-variable[time-variable] draw --> wave-calls[wave-calls] wave-calls --> wave-loop[wave-loop] wave-loop --> sine-calculation[sine-calculation] sine-calculation --> wave-loop wave-loop --> wave-calls wave-calls --> draw draw --> windowresized[windowresized] click setup href "#fn-setup" click draw href "#fn-draw" click gradient-setup href "#sub-gradient-setup" click gradient-apply href "#sub-gradient-apply" click time-variable href "#sub-time-variable" click wave-calls href "#sub-wave-calls" click wave-loop href "#sub-wave-loop" click sine-calculation href "#sub-sine-calculation" click windowresized href "#fn-windowresized"

๐Ÿ“ Code Breakdown

setup()

setup() runs once when the sketch starts. Here we create a full-screen canvas that will display our ocean waves. windowWidth and windowHeight are p5.js variables that automatically contain the browser window's dimensions.

function setup(){createCanvas(windowWidth,windowHeight);}

Line by Line:

createCanvas(windowWidth,windowHeight)
Creates a canvas that fills the entire browser window using the current window dimensions

draw()

draw() runs 60 times per second, creating smooth animation. Each frame, we redraw the background gradient and three waves at slightly different positions. The waves move because we pass the time variable t to the wave function, which uses it in a sine calculation. Different speed values (0.6, 0.4, 0.25) make each wave move at a different rate, creating a natural, layered ocean effect.

function draw(){
  let g=drawingContext.createLinearGradient(0,0,0,height);
  g.addColorStop(0,'#87cefa');g.addColorStop(1,'#004f7a');
  drawingContext.fillStyle=g;drawingContext.fillRect(0,0,width,height);
  noStroke();let t=frameCount*0.02;
  wave(height*0.7,20,color('#a7d8ff'),0.6,t);
  wave(height*0.73,25,color('#64b5f6'),0.4,t);
  wave(height*0.76,30,color('#1e88e5'),0.25,t);
}

๐Ÿ”ง Subcomponents:

calculation Background Gradient Creation let g=drawingContext.createLinearGradient(0,0,0,height); g.addColorStop(0,'#87cefa');g.addColorStop(1,'#004f7a');

Creates a vertical gradient that transitions from light sky blue at the top to deep ocean blue at the bottom

calculation Apply Gradient to Canvas drawingContext.fillStyle=g;drawingContext.fillRect(0,0,width,height);

Sets the gradient as the fill style and draws a rectangle covering the entire canvas

calculation Animation Time Variable let t=frameCount*0.02;

Creates a time variable that increases each frame, used to animate the waves smoothly

for-loop Draw Three Waves wave(height*0.7,20,color('#a7d8ff'),0.6,t); wave(height*0.73,25,color('#64b5f6'),0.4,t); wave(height*0.76,30,color('#1e88e5'),0.25,t);

Calls the wave function three times with different parameters to create layered waves at different heights, colors, and speeds

Line by Line:

let g=drawingContext.createLinearGradient(0,0,0,height)
Creates a linear gradient object that goes vertically from top (0) to bottom (height). drawingContext gives us access to the underlying canvas drawing API
g.addColorStop(0,'#87cefa')
Adds a light sky blue color at position 0 (the top of the gradient)
g.addColorStop(1,'#004f7a')
Adds a deep ocean blue color at position 1 (the bottom of the gradient)
drawingContext.fillStyle=g
Sets the gradient as the current fill color for all subsequent drawing
drawingContext.fillRect(0,0,width,height)
Draws a rectangle covering the entire canvas with the gradient fill
noStroke()
Tells p5.js not to draw outlines around shapes - we only want filled shapes
let t=frameCount*0.02
Creates a time variable by multiplying the frame number by 0.02. This increases smoothly each frame and controls wave animation
wave(height*0.7,20,color('#a7d8ff'),0.6,t)
Draws the first (lightest) wave at 70% down the screen with amplitude 20, light blue color, speed 0.6, and current time t
wave(height*0.73,25,color('#64b5f6'),0.4,t)
Draws the second wave at 73% down the screen with amplitude 25, medium blue color, speed 0.4, and current time t
wave(height*0.76,30,color('#1e88e5'),0.25,t)
Draws the third (darkest) wave at 76% down the screen with amplitude 30, dark blue color, speed 0.25, and current time t

wave(yBase, amp, col, s, t)

This function creates one wave by using a sine function to calculate smooth up-and-down motion. The key formula is sin(x*a-t*s)*amp: the x*a part creates the wave pattern across the screen, the -t*s part makes it animate (the negative sign makes it move left), and *amp scales it to the right height. By calling this function three times with different parameters, we create the layered effect.

function wave(yBase,amp,col,s,t){
  fill(col);beginShape();
  for(let x=0;x<=width+20;x+=20){
    let a=0.01,y=yBase+sin(x*a-t*s)*amp;
    vertex(x,y);
  }
  vertex(width,height);vertex(0,height);endShape(CLOSE);
}

๐Ÿ”ง Subcomponents:

for-loop Generate Wave Points for(let x=0;x<=width+20;x+=20){ let a=0.01,y=yBase+sin(x*a-t*s)*amp; vertex(x,y); }

Loops across the canvas width, calculating sine wave points every 20 pixels and adding them as vertices to create the wave shape

calculation Sine Wave Formula let a=0.01,y=yBase+sin(x*a-t*s)*amp

Calculates the y position of each point using a sine wave formula that creates smooth oscillation

Line by Line:

function wave(yBase,amp,col,s,t)
Defines a function that takes 5 parameters: yBase (vertical position), amp (wave height), col (color), s (speed), and t (time)
fill(col)
Sets the fill color to the color passed in (one of the blue shades)
beginShape()
Starts creating a shape by collecting vertices. We'll add points to form the wave
for(let x=0;x<=width+20;x+=20)
Loops from x=0 to just beyond the canvas width, incrementing by 20 pixels each time
let a=0.01
Sets a frequency value of 0.01 that controls how tight or loose the wave oscillations are
y=yBase+sin(x*a-t*s)*amp
Calculates the y position: start at yBase, add a sine wave that oscillates based on x position and time, multiplied by amplitude. The (x*a-t*s) part makes the wave move over time
vertex(x,y)
Adds a point to the shape at position (x,y)
vertex(width,height)
Adds a point at the bottom-right corner to close the wave shape
vertex(0,height)
Adds a point at the bottom-left corner to complete the filled shape
endShape(CLOSE)
Finishes the shape and closes it by connecting the last point back to the first, creating a filled polygon

windowResized()

windowResized() is a special p5.js function that automatically gets called whenever the browser window is resized. By calling resizeCanvas() here, we ensure the ocean waves always fill the entire screen, no matter how large or small the window is. This makes the sketch responsive to different screen sizes.

function windowResized(){resizeCanvas(windowWidth,windowHeight);}

Line by Line:

resizeCanvas(windowWidth,windowHeight)
Automatically resizes the canvas to match the new window dimensions whenever the browser window is resized

๐Ÿ“ฆ Key Variables

g object

Stores the gradient object created by createLinearGradient. This gradient transitions from light blue to dark blue and is used to fill the background

let g=drawingContext.createLinearGradient(0,0,0,height);
t number

Stores the animation time variable (frameCount * 0.02). This increases each frame and controls how far the waves have moved, creating smooth animation

let t=frameCount*0.02;
x number

Loop variable in the wave function that tracks the horizontal position as we generate wave points across the canvas

for(let x=0;x<=width+20;x+=20)
a number

Frequency value (0.01) that controls the wavelength - how tight or loose the wave oscillations are. Smaller values = longer waves

let a=0.01
y number

Calculated y position of each wave point. Starts at yBase and oscillates up and down based on the sine function

y=yBase+sin(x*a-t*s)*amp

๐Ÿงช Try This!

Experiment with the code by making these changes:

  1. Change the gradient colors by modifying '#87cefa' and '#004f7a' in the draw() function. Try '#ff69b4' (pink) and '#ff1493' (deep pink) to create a sunset ocean
  2. Adjust the time multiplier from 0.02 to 0.05 or 0.01 in the line 'let t=frameCount*0.02' to make waves move faster or slower
  3. Change the amplitude values in the three wave() calls from 20, 25, 30 to 10, 15, 20 to create smaller, gentler waves
  4. Modify the speed values (0.6, 0.4, 0.25) in the wave() calls to 0.8, 0.5, 0.3 to make all waves move at different speeds
  5. Change the frequency value 'a' from 0.01 to 0.005 in the wave() function to create longer, more stretched-out waves
  6. Add a fourth wave by copying one of the wave() calls and changing the yBase to height*0.79 with a new color like '#0d47a1'
Open in Editor & Experiment โ†’

๐Ÿ”ง Potential Improvements

Here are some ways this code could be enhanced:

PERFORMANCE draw() function - gradient creation

The gradient is recreated every single frame (60 times per second) even though it never changes. This is wasteful computation

๐Ÿ’ก Move the gradient creation to setup() and store it in a global variable, then reuse it in draw(). This way it's only created once

STYLE wave() function - variable naming

Single-letter variable names like 'a', 's', 't', 'x', 'y' are hard to understand. The parameter names yBase, amp, col, s are abbreviated

๐Ÿ’ก Use descriptive names: rename 'a' to 'frequency', 's' to 'speed', 't' to 'time', 'col' to 'color', 'amp' to 'amplitude' for better readability

BUG wave() function - loop boundary

The loop goes to 'width+20' which means the last wave point might be drawn slightly off-screen, potentially causing visual artifacts

๐Ÿ’ก Change the loop condition to 'x<=width' to ensure all points stay within canvas bounds

FEATURE draw() function

The wave speeds and amplitudes are hardcoded, making it difficult to adjust the overall effect without editing multiple lines

๐Ÿ’ก Create global variables for wave parameters (speeds, amplitudes, colors) at the top of the sketch so they're easy to modify in one place

Preview

AI Ocean Waves - Calming Meditation - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of AI Ocean Waves - Calming Meditation - Code flow showing setup, draw, wave, windowresized
Code Flow Diagram