Fireflies Animation with Background Music using JavaScript and jQuery

fireflies javascript
This is a JavaScript animation where it shows a background of a picnic area in the woods, surrounded by glowing fireflies. The code was originally wrote by Andrew Reifman. I further develop the code and added a background music that reflects the environment, then a fade in and a fade out effect. The code is using a combination of classic JavaScript and jQuery functions. The background music is from Final Fantasy VII entitled Aerith’s (Aeris) Theme composed by Nobuo Uematsu. No copyright infringement intended, this is only for personal non-commercial use.

You can download the file here. The file is a zip file compose of the HTML file, CSS, JavaScript, an image file, and 2 audio files, one for preloading purpose and the other one is the main background music.

The code is using canvas animation effect similar to this one.

The Code

fireflies code

In this project, I am linking to Google’s Ajax (Asynchronous JavaScript and XML) library, specifically jQuery v.3.3.1. You may need internet connection to be able to connect to Google’s Library. Without jQuery, the animation won’t work as several functions including the main initiation sequence is dependent on jQuery’s ready function. I am also using fadeIn and fadeOut jQuery effects.

I will avoid talking about the HTML and CSS files. Let’s focus more on the JavaScript part.

HTML File

<!DOCTYPE html>
<html>
	<head>
		<title>Fireflies</title>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<link href="css/stylesheet.css" type="text/css" rel="stylesheet" />
	</head>
	<body>
		<iframe src="5-seconds-of-silence.mp3" allow="autoplay" style="display:none"></iframe>
		<audio preload="auto" id="music">
			<source src="aeriths_theme.ogg" type="audio/ogg">
		</audio>
		<script>
			window.onload = function(){
				music = document.getElementById("music");
				music.play();
			}
		</script>
 		<canvas id="portrait"></canvas>
		<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
		<script type="text/javascript" src="javascript/fireflies.js"></script>
	</body>
</html>

CSS File

body {
	background-color: #000;
	text-align: center;
}

canvas{
	width: 500px;
	height: 333px;
}

#portrait{
	display: none;
	background:url("../firefly_woods.jpg");
	top: 50%;
	transform: translateX(-50%) translateY(-50%);
	position: absolute;
}

JavaScript

var cw = 500;
var ch = 333;
var canvas;
var ctx;
var fattr;
var firefly = new Array();
var rint = 50;
//var music = new Audio();
//music.src = "aeriths_theme.ogg";

$(document).ready(function(){
	$("#portrait").fadeIn(2000);
//	music.play();
	canvas = document.getElementById('portrait');
	$(canvas).attr('width', cw).attr('height',ch);
	ctx = canvas.getContext('2d');
	for(var i = 0; i < 50; i++) {
		firefly[i] = new Circle();
		firefly[i].reset();
	}
	setInterval(draw,rint);
	setTimeout(fadeOut,240000);
	function fadeOut(){
		$("#portrait").fadeOut(2000);
	}
});

function draw() {
	ctx.clearRect(0,0,cw,ch);
	for(var i = 0; i < firefly.length; i++) {
		firefly[i].fade();
		firefly[i].move();
		firefly[i].draw();
	}
}

function Circle() {
	this.s = {ttl:8000, xmax:5, ymax:2, rmax:4, rt:1, xdef:960, ydef:540, xdrift:4, ydrift: 4, random:true, blink:true};

	this.reset = function() {
		this.x = (this.s.random ? cw*Math.random() : this.s.xdef);
		this.y = (this.s.random ? ch*Math.random() : this.s.ydef);
		this.r = ((this.s.rmax-1)*Math.random()) + 1;
		this.dx = (Math.random()*this.s.xmax) * (Math.random() < .5 ? -1 : 1);
		this.dy = (Math.random()*this.s.ymax) * (Math.random() < .5 ? -1 : 1);
		this.hl = (this.s.ttl/rint)*(this.r/this.s.rmax);
		this.rt = Math.random()*this.hl;
		this.s.rt = Math.random()+1;
		this.stop = Math.random()*.2+.4;
		this.s.xdrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
		this.s.ydrift *= Math.random() * (Math.random() < .5 ? -1 : 1);
	}

	this.fade = function() {
		this.rt += this.s.rt;
	}

	this.draw = function() {
		if(this.s.blink && (this.rt <= 0 || this.rt >= this.hl)) this.s.rt = this.s.rt*-1;
		else if(this.rt >= this.hl) this.reset();
		var newo = 1-(this.rt/this.hl);
		ctx.beginPath();
		ctx.arc(this.x,this.y,this.r,0,Math.PI*2,true);
		ctx.closePath();
		var cr = this.r*newo;
		fattr = ctx.createRadialGradient(this.x,this.y,0,this.x,this.y,(cr <= 0 ? 1 : cr));
		fattr.addColorStop(0.0, 'rgba(253,219,163,'+newo+')');
		fattr.addColorStop(this.stop, 'rgba(238,180,28,'+(newo*.2)+')');
		fattr.addColorStop(1.0, 'rgba(253,219,163,0)');
		ctx.fillStyle = fattr;
		ctx.fill();
	}

	this.move = function() {
		this.x += (this.rt/this.hl)*this.dx;
		this.y += (this.rt/this.hl)*this.dy;
		if(this.x > cw || this.x < 0) this.dx *= -1;
		if(this.y > ch || this.y < 0) this.dy *= -1;
	}

	this.getX = function() { return this.x; }
	this.getY = function() { return this.y; }
}

In the JavaScript, I disabled var music, music.src, and music.play() because of the issue with Uncaught (in promise) DOMException, you guys can read about that here. Apparently, most browsers now prevent bgms from autoplaying. It now demands user-interaction. Probably, this was due to complaints of users being given the jump scare by sites that play loud audio upon loading of a page. Also, since we are using jQuery, an ajax, then you can expect contents to get loaded asynchronously. If an audio hasn’t completed loading, audio playing will be rejected.

Now, going to the rest of the code… note that I may be skipping some functions here. You may need to research on some of them as I will be highlighting only some of what I think are important functions.

Line 11: $(document).ready is a jQuery function that will only run a function once everything is ready.

Line 12: This code is jQuery method for the fade in effect. 2000 is the time in takes for the object to load completely. Higher value means longer.

Line 15: .attr is a jQuery method that sets or returns attributes and values of the selected element. Since cw is 500 and ch is 333, then in the code, we are setting width of the canvas to 500px wide and height to 333px high.

Line 17: Code for firefly generation. It is a loop that runs the firefly Circle function and reset. This creates fireflies and makes them disappear.

Line 21: setInterval fires draw function every 0.050 sec. (rint = 50).

Line 22: setTimeout will fire fadeOut function after 240000 or 240 secs.

Line 23: jQuery method that makes the portrait or the canvas fade out.

Line 28: This runs the effects that are applied to the Circles (our fireflies).

Line 37: Calls the Circles function otherwise known as our canvas particle animation. In this set of code, we are setting up our objects, which will be applied to our fireflies’ behavior.

Line 38 contains the values for:
· ttl or time_to_live, which is used to calculate hl or the half-life of each particle.
· xmax and ymax stands for x_maxspeed and y_maxspeed. It defines the maximum number of pixels a particle can move each frame.
· rmax or radius_max is the maximum radius a particle can achieve. This defines the maximum size a firefly can glow.
· rt is used in conjunction with hl to determine the ratio of maximum speed and full opacity of each particle in each frame.
· xdef, ydef, xdrift, ydrift are values which will be use for the particles movement. random:true means its going to be random and blink:true means its going to blink.

Line 40: this function resets the fireflies’ behavior, making them disappear and reappear in another location within our portrait. Their behavior also resets into another random behavior.

Line 54: This adds the value of rt to the object this.s rt’s attribute. By doing this, the ratio to the half-life increases, making our firefly go dim and dimmer.

Line 58: this.draw function iterates over the array and calls each necessary function of each particle to animate its behavior.

Line 62: creates a drawing path.

Line 63: turns our object into a circle.

Line 64: end our drawing pathway.

Line 67, 68, 69: .addColorStop method adds a new color stop, defined by an offset and a color, to a given canvas gradient.

Line 70: Applies the style to our firefly, in this case, the radial gradient effect.

Line 71: Applies the style to all fireflies in the array.

Line 74: Creates a random firefly movement.

Line 81 and 82: Applies the movement.

This is the final output:

YouTube:

CodePen:

Press rerun to reload the page and play the music.

See the Pen
Fire Flies with Background Music
by AL Meta (@Altometa)
on CodePen.

Follow me at:

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.