AI Emoji Rain - Colorful Emojis Falling from the Sky

This sketch creates a cheerful emoji rain animation where colorful emojis (hearts, stars, suns, moons, and more) continuously fall from the top of the canvas with realistic gravity and bouncing physics. Clicking anywhere spawns a burst of 10 emojis at that location, and all emojis fade away after bouncing on the ground.

๐ŸŽ“ Concepts You'll Learn

Animation loopPhysics simulation (gravity and velocity)Array manipulationObject propertiesCollision detectionColor interpolationMouse interactionResponsive canvasAlpha transparencyRandom generation

๐Ÿ”„ Code Flow

Code flow showing setup, spawn, draw, mousepressed, windowresized

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

graph TD start[Start] --> setup[setup] setup --> draw[draw loop] draw --> gradientbackground[Gradient Background] gradientbackground --> randomspawn[Random Emoji Spawn] randomspawn --> physicsloop[Emoji Physics and Rendering Loop] physicsloop --> gravityapplication[Apply Gravity] gravityapplication --> positionupdate[Update Position] positionupdate --> collisiondetection[Collision Detection] collisiondetection --> bouncelogic[Bounce Logic] bouncelogic --> fadeout[Fade Out After Bounce] fadeout --> removal[Remove Faded Emojis] removal --> rendering[Draw Emoji] rendering --> draw click setup href "#fn-setup" click draw href "#fn-draw" click gradientbackground href "#sub-gradient-background" click randomspawn href "#sub-random-spawn" click physicsloop href "#sub-physics-loop" click gravityapplication href "#sub-gravity-application" click positionupdate href "#sub-position-update" click collisiondetection href "#sub-collision-detection" click bouncelogic href "#sub-bounce-logic" click fadeout href "#sub-fade-out" click removal href "#sub-removal" click rendering href "#sub-rendering" draw --> mousepressed[mousePressed] mousepressed --> burstspawn[Emoji Burst Spawn] burstspawn --> draw click mousepressed href "#fn-mousepressed" click burstspawn href "#sub-burst-spawn" setup --> windowresized[windowResized] click windowresized href "#fn-windowresized"

๐Ÿ“ Code Breakdown

setup()

setup() runs once when the sketch starts. It's where you initialize the canvas size, set up colors, and configure drawing settings. The two colors here create a sky-like gradient effect.

function setup(){
  createCanvas(windowWidth,windowHeight);
  textAlign(CENTER,CENTER);
  c1=color(135,206,250);c2=color(180,228,255);
}

Line by Line:

createCanvas(windowWidth,windowHeight)
Creates a canvas that fills the entire browser window using the window's current width and height
textAlign(CENTER,CENTER)
Sets text alignment to center both horizontally and vertically, so emojis are drawn from their center point
c1=color(135,206,250)
Creates a light blue color and stores it in c1 - this is the top color of the gradient background
c2=color(180,228,255)
Creates a slightly lighter blue color and stores it in c2 - this is the bottom color of the gradient background

spawn(x, y)

spawn() is a helper function that creates a new emoji object with random properties and adds it to the emojis array. Each emoji has its own position, velocity, size, and character. The object-oriented approach makes it easy to manage many independent emojis.

function spawn(x,y){
  emojis.push({x,y,vy:random(1,3),vx:random(-0.5,0.5),s:random(32,56),ch:random(chars),b:false,a:255});
}

๐Ÿ”ง Subcomponents:

calculation Emoji Object Creation {x,y,vy:random(1,3),vx:random(-0.5,0.5),s:random(32,56),ch:random(chars),b:false,a:255}

Creates a new emoji object with position, velocity, size, character, bounce state, and alpha properties

Line by Line:

emojis.push({x,y,vy:random(1,3),vx:random(-0.5,0.5),s:random(32,56),ch:random(chars),b:false,a:255})
Creates a new emoji object with: x,y position; vy (vertical velocity) between 1-3 pixels per frame; vx (horizontal velocity) between -0.5 to 0.5 for slight side movement; s (size) between 32-56 pixels; ch (character) randomly chosen from the chars array; b (bounced flag) set to false; a (alpha/transparency) set to 255 (fully opaque). This object is added to the emojis array.

draw()

draw() is the main animation loop that runs 60 times per second. It handles three main tasks: drawing the background gradient, spawning new emojis randomly, and updating/rendering all existing emojis with physics simulation. The backwards loop is crucial for safely removing items during iteration.

function draw(){
  for(let y=0;y<height;y++)stroke(lerpColor(c1,c2,y/height)),line(0,y,width,y);
  if(random()<0.04)spawn(random(width),-20);
  noStroke();
  for(let i=emojis.length-1;i>=0;i--){
    let e=emojis[i];
    e.vy+=g;e.x+=e.vx;e.y+=e.vy;
    if(e.y+e.s/2>height){
      e.y=height-e.s/2;
      if(!e.b){e.vy*=-0.6;e.b=true;}else e.vy=0;
    }
    if(e.b)e.a-=4;
    if(e.a<=0){emojis.splice(i,1);continue;}
    fill(0,0,0,e.a);textSize(e.s);text(e.ch,e.x,e.y);
  }
}

๐Ÿ”ง Subcomponents:

for-loop Gradient Background for(let y=0;y<height;y++)stroke(lerpColor(c1,c2,y/height)),line(0,y,width,y)

Draws horizontal lines across the canvas, interpolating between two blue colors to create a smooth sky gradient from top to bottom

conditional Random Emoji Spawn if(random()<0.04)spawn(random(width),-20)

Has a 4% chance each frame to spawn a new emoji at a random x position above the canvas

for-loop Emoji Physics and Rendering Loop for(let i=emojis.length-1;i>=0;i--)

Iterates through all emojis in reverse order, updating their physics and drawing them

calculation Apply Gravity e.vy+=g

Increases vertical velocity by gravity constant (0.3), making emojis accelerate downward

calculation Update Position e.x+=e.vx;e.y+=e.vy

Updates emoji's x and y position based on its horizontal and vertical velocity

conditional Bounce Collision Detection if(e.y+e.s/2>height)

Checks if emoji has hit the bottom of the canvas by comparing its bottom edge to canvas height

conditional Bounce Behavior if(!e.b){e.vy*=-0.6;e.b=true;}else e.vy=0

On first bounce, reverses velocity and reduces it by 40% (multiply by -0.6); on subsequent frames, sets velocity to 0

conditional Fade Out After Bounce if(e.b)e.a-=4

Decreases alpha by 4 each frame after emoji bounces, creating a fade-out effect

conditional Remove Faded Emojis if(e.a<=0){emojis.splice(i,1);continue;}

Removes emoji from array when fully transparent to free up memory

calculation Draw Emoji fill(0,0,0,e.a);textSize(e.s);text(e.ch,e.x,e.y)

Sets black color with current alpha, sets text size, and draws the emoji character at its current position

Line by Line:

for(let y=0;y<height;y++)stroke(lerpColor(c1,c2,y/height)),line(0,y,width,y)
Creates a gradient background by drawing horizontal lines from top to bottom. lerpColor interpolates between c1 (light blue) and c2 (lighter blue) based on y position, creating a smooth color transition
if(random()<0.04)spawn(random(width),-20)
Generates a random number between 0-1. If it's less than 0.04 (4% chance), spawn a new emoji at a random x position and y position of -20 (above the visible canvas)
noStroke()
Disables stroke/outline for text rendering so emojis appear clean without borders
for(let i=emojis.length-1;i>=0;i--)
Loops through the emojis array backwards (from last to first). Backwards iteration is important because we'll be removing items from the array during the loop
let e=emojis[i]
Creates a shorthand reference 'e' to the current emoji object to make the code more readable
e.vy+=g
Applies gravity by adding 0.3 to vertical velocity each frame, making emojis accelerate downward realistically
e.x+=e.vx;e.y+=e.vy
Updates emoji position: adds horizontal velocity to x position and vertical velocity to y position, creating movement
if(e.y+e.s/2>height)
Checks if emoji has hit the bottom: e.y is the center, e.s/2 is half the size (radius), so this checks if the bottom edge exceeds canvas height
e.y=height-e.s/2
Positions emoji exactly at the bottom of the canvas so it doesn't go past the edge
if(!e.b){e.vy*=-0.6;e.b=true;}else e.vy=0
First bounce: reverses velocity (multiply by -1) and reduces it by 40% (multiply by 0.6 total), then sets bounced flag to true. Subsequent frames: sets velocity to 0 so emoji stays still
if(e.b)e.a-=4
After bouncing, decreases alpha by 4 each frame, creating a fade-out effect
if(e.a<=0){emojis.splice(i,1);continue;}
When alpha reaches 0 or below, removes the emoji from the array using splice(), and continues to the next iteration to avoid errors
fill(0,0,0,e.a);textSize(e.s);text(e.ch,e.x,e.y)
Sets fill color to black with current alpha transparency, sets text size to emoji's size, and draws the emoji character at its current x,y position

mousePressed()

mousePressed() is a p5.js built-in function that runs whenever the user clicks. This sketch uses it to create an interactive element - clicking spawns a burst of emojis, making the animation more engaging and responsive to user input.

function mousePressed(){for(let i=0;i<10;i++)spawn(mouseX,mouseY);}

๐Ÿ”ง Subcomponents:

for-loop Emoji Burst Spawn for(let i=0;i<10;i++)spawn(mouseX,mouseY)

Spawns 10 emojis at the mouse click location

Line by Line:

for(let i=0;i<10;i++)spawn(mouseX,mouseY)
Loops 10 times, and each time calls spawn() with the current mouse position (mouseX, mouseY), creating a burst of 10 emojis at the click location

windowResized()

windowResized() is a p5.js built-in function that automatically runs when the browser window is resized. This ensures the canvas always fills the entire window, making the sketch responsive to different screen sizes.

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

Line by Line:

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

๐Ÿ“ฆ Key Variables

emojis array

Stores all active emoji objects. Each object contains position (x, y), velocity (vx, vy), size (s), character (ch), bounce state (b), and alpha/transparency (a)

let emojis=[];
chars array

Stores the 10 emoji characters that can be randomly selected when spawning new emojis

let chars=['โค๏ธ','โญ','โ˜€๏ธ','๐ŸŒ™','๐Ÿ”ฅ','๐ŸŒˆ','๐Ÿ’ง','๐Ÿ€','๐ŸŒธ','๐Ÿ˜ƒ'];
g number

Gravity constant that controls how fast emojis accelerate downward. Added to vertical velocity each frame

let g=0.3;
c1 color

Stores the top color of the gradient background (light blue: RGB 135, 206, 250)

let c1=color(135,206,250);
c2 color

Stores the bottom color of the gradient background (lighter blue: RGB 180, 228, 255)

let c2=color(180,228,255);

๐Ÿงช Try This!

Experiment with the code by making these changes:

  1. Change the gravity constant 'g' from 0.3 to 0.5 or 1.0 and watch how much faster emojis fall and accelerate
  2. Modify the spawn probability from 0.04 to 0.1 in the line 'if(random()<0.04)' to make emojis spawn much more frequently - watch the rain get heavier
  3. Change the bounce damping from -0.6 to -0.9 in the line 'e.vy*=-0.6' to make emojis bounce higher and more realistically
  4. Increase the burst spawn count from 10 to 50 in the mousePressed function to create a massive emoji explosion on click
  5. Add more emojis to the chars array like '๐ŸŽ‰', '๐ŸŽˆ', '๐ŸŒบ' to increase the variety of falling emojis
  6. Change the fade-out speed from 'e.a-=4' to 'e.a-=1' to make emojis fade out much slower after bouncing
  7. Modify the initial spawn height from -20 to -100 to make emojis fall from higher above the canvas
Open in Editor & Experiment โ†’

๐Ÿ”ง Potential Improvements

Here are some ways this code could be enhanced:

BUG draw() - collision detection line 'if(e.y+e.s/2>height)'

Emojis can get stuck bouncing at the bottom if gravity and velocity create an infinite loop of small bounces

๐Ÿ’ก Add a check to ensure velocity is small enough before allowing bounces: 'if(Math.abs(e.vy) < 0.1) e.vy = 0;' to stop bouncing once velocity is negligible

PERFORMANCE draw() - gradient background loop

Drawing 1000+ horizontal lines every frame (one per pixel height) is computationally expensive and unnecessary

๐Ÿ’ก Create the gradient once in setup() using createGraphics() or use a simpler background with fewer lines: 'for(let y=0;y<height;y+=2)' to draw every other line

STYLE Global variable declarations

Variable names are abbreviated (g, c1, c2, e, b, a, s, ch, vx, vy) making the code hard to read and maintain

๐Ÿ’ก Use descriptive names: 'gravity', 'topColor', 'bottomColor', 'emoji', 'bounced', 'alpha', 'size', 'character', 'velocityX', 'velocityY' for better code clarity

FEATURE spawn() function

All emojis are drawn in black with no color variation, making them less visually interesting

๐Ÿ’ก Add a color property to emoji objects and randomly assign colors: 'col:color(random(255),random(255),random(255))' then use 'fill(e.col)' when drawing

BUG draw() - emoji removal line 'emojis.splice(i,1);continue;'

The 'continue;' statement is unnecessary here since it's the last statement in the loop anyway

๐Ÿ’ก Remove the 'continue;' statement as it doesn't affect functionality, just remove it for cleaner code

FEATURE draw() - physics simulation

Emojis don't rotate or tumble as they fall, making the animation less dynamic

๐Ÿ’ก Add a rotation property to emojis and increment it each frame: 'e.rot+=random(0.05,0.1)' then use 'push(); rotate(e.rot); text(...); pop();' when drawing

Preview

AI Emoji Rain - Colorful Emojis Falling from the Sky - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of AI Emoji Rain - Colorful Emojis Falling from the Sky - Code flow showing setup, spawn, draw, mousepressed, windowresized
Code Flow Diagram