<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<style>
html,
body {
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
font-family: Helvetica, Arial;
color: #ffffff;
}
body {
background: linear-gradient(0deg, #aabbbb, #88aadd);
}
#stage, #smoke {
position: absolute;
top: 0;
left: 0;
}
#stage {
z-index: 20;
}
#smoke {
z-index: 5;
}
.volcano-container {
z-index: 10;
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.volcano {
position: absolute;
border: 380px solid transparent;
border-left: 140px solid transparent;
border-bottom: 200px solid #240904;
width: 0;
height: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.volcano.flipped {
transform: scaleX(-1);
}
.lip {
position: absolute;
left: 0;
right: 0;
bottom: 0;
margin: auto;
width: 300px;
height: 240px;
background-color: #240904;
border-radius: 200px;
}
.lip .lava {
position: absolute;
left: 0;
right: 0;
top: 10px;
margin: auto;
width: 270px;
height: 230px;
background-color: #fa7510;
border-radius: 200px;
clip-path: ellipse(120px 60px at top);
}
.lip .mask {
position: absolute;
top: 80px;
left: 0;
right: 0;
margin: auto;
background-color: #240904;
width: 290px;
height: 300px;
}
.toggle {
display: none;
z-index: 100;
position: absolute;
top: 10px;
left: 10px;
}
</style>
</HEAD>
<BODY>
<canvas id="smoke"></canvas>
<canvas id="stage"></canvas>
<div class="volcano-container">
<div class="volcano"></div>
<div class="volcano flipped"></div>
<div class="lip">
<div class="lava"></div>
<div class="mask"></div>
</div>
</div>
<div class="toggle">
<label for="awesome">
<input type="checkbox" id="awesome" /> <strong>AWESOME MODE</strong>
</label>
</div>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script>
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
// Best viewed in Chrome
//=============================
// Consts
//=============================
var MAX_WIDTH = 12;
var FPS = 60;
//=============================
// Helpers
//=============================
var getTimestamp = function getTimestamp() {
return new Date().getTime();
};
var random = function random() {
var max = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var signed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
return signed ? (Math.random() - 0.5) * 2 * max : Math.random() * max;
};
var getPower = function getPower() {
var power = (getTimestamp() - mouseStart) / 150;
return power > 30 ? 30 : power;
};
var shakeVolcano = function shakeVolcano(power) {
$volcano.css({
left: random(power, true),
bottom: -1 * random(power)
});
$lava.css({
left: random(power, true),
top: 10 + random(power) / 2,
width: random(power) + 260
});
};
//=============================
// Main
//=============================
var targetDelta = 1000 / FPS;
var stage = document.getElementById('stage');
var ctx = stage.getContext('2d');
var smoke = document.getElementById('smoke');
var ctx2 = smoke.getContext('2d');
var particles = [];
var AWESOME_MODE = false;
var mouseDown = false;
var isExploding = false;
var stageWidth = 0;
var stageHeight = 0;
var previousTimestamp = getTimestamp();
var previousRender = getTimestamp();
var previousPower = 0;
var mouseStart = getTimestamp();
var mouseEnd = getTimestamp();
var $volcano = void 0;
var $lava = void 0;
var generateParticles = function generateParticles() {
var amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 20;
var power = arguments[1];
for (var i = 0; i < amount; i++) {
particles.push(new Particle(power));
}
};
var loop = function loop() {
if (getTimestamp() - previousTimestamp < targetDelta) {
requestAnimationFrame(loop);
return;
}
ctx.globalCompositeOperation = 'lighter';
if (!AWESOME_MODE) {
ctx.clearRect(0, 0, stageWidth, stageHeight);
}
ctx2.clearRect(0, 0, stageWidth, stageHeight);
if (mouseDown) {
generateParticles(random(2) + 1, getPower() / 2);
shakeVolcano(getPower());
}
if (isExploding && previousPower > 0 && !mouseDown) {
shakeVolcano(previousPower);
previousPower -= 0.35;
if (previousPower < 1) {
isExploding = false;
}
}
// constant particles
if (random() < 0.3) {
generateParticles(1, 1);
}
// smoke effects
if (random() < 0.08) {
particles.push(new Smoke());
}
// animate
particles.forEach(function (particle) {
particle.animate();
particle.render();
});
// remove out of bounds particles
particles = particles.filter(function (particle) {
if (particle instanceof Smoke && particle.y + particle.width > 0) {
return true;
} else if (particle instanceof Particle && particle.y < stageHeight && particle.x > 0 - particle.width && particle.x < stageWidth + particle.width) {
return true;
} else {
return false;
}
});
previousTimestamp = getTimestamp();
requestAnimationFrame(loop);
};
var Particle = function () {
function Particle(oPower) {
_classCallCheck(this, Particle);
var power = oPower || random(5);
this.x = stageWidth / 2 + random(80, true);
this.y = stageHeight - 200 + random(20, true);
this.width = random(MAX_WIDTH) + 1;
this.red = Math.floor(210 + this.width * 2);
this.green = Math.floor(90 + this.width * 3);
this.blue = Math.floor(30 + this.width * 2);
this.alpha = 1;
this.speed = power / (this.width * 0.13);
this.angle = random(45);
this.hasBounced = false;
this.velocityY = Math.abs(Math.sin(this.angle)) * this.speed;
this.velocityX = Math.cos(this.angle) * this.speed / 2;
this.xDirection = this.velocityX > 0;
if (Math.abs(this.velocityX) > 2) {
this.velocityX = this.velocityX / 2;
}
}
_createClass(Particle, [{
key: 'animate',
value: function animate() {
this.x -= this.velocityX;
this.y -= this.velocityY;
// add gravity
this.velocityY -= this.width / (this.hasBounced ? 170 : 100);
if (!this.hasBounced && random() < 0.1 && this.y > stageHeight - 150 && this.x > stageWidth / 2 - 180 && this.x < stageWidth / 2 + 180) {
this.hasBounced = true;
this.velocityX = Math.sin(random(45)) + random(2) * this.xDirection;
this.velocityY /= 8;
}
}
}, {
key: 'render',
value: function render() {
var colour = this.getColour();
ctx.beginPath();
ctx.arc(this.x, this.y, this.width, 0, Math.PI * 2, true);
ctx.lineWidth = this.width;
ctx.fillStyle = colour;
//ctx.shadowBlur = random(20);
//ctx.shadowColor = colour;
ctx.fill();
}
}, {
key: 'getColour',
value: function getColour(red, green, blue, alpha) {
return 'rgba(' + (red || this.red) + ', ' + (green || this.green) + ', ' + (blue || this.blue) + ', ' + (alpha || this.alpha) + ')';
}
}]);
return Particle;
}();
var Smoke = function () {
function Smoke() {
_classCallCheck(this, Smoke);
this.x = stageWidth / 2 + random(75, true);
this.y = stageHeight;
this.width = random(80) + 50;
this.red = 100;
this.green = 100;
this.blue = 100;
this.alpha = random() + 0.3;
this.speed = random(2) + 1;
}
_createClass(Smoke, [{
key: 'animate',
value: function animate() {
//this.x += random(2, true);
this.y -= this.speed;
}
}, {
key: 'render',
value: function render() {
var colour = this.getColour();
ctx2.beginPath();
ctx2.arc(this.x, this.y, this.width, 0, Math.PI * 2, true);
ctx2.lineWidth = this.width;
ctx2.fillStyle = colour;
ctx2.fill();
}
}, {
key: 'getColour',
value: function getColour(red, green, blue, alpha) {
return 'rgba(' + (red || this.red) + ', ' + (green || this.green) + ', ' + (blue || this.blue) + ', ' + (alpha || this.alpha) + ')';
}
}]);
return Smoke;
}();
//=============================
// Setup
//=============================
var updateCanvasSize = function updateCanvasSize() {
stageWidth = window.innerWidth;
stageHeight = window.innerHeight;
stage.width = stageWidth;
stage.height = stageHeight;
smoke.width = stageWidth;
smoke.height = stageHeight;
particles = [];
};
$(window).on('mousedown', function (e) {
mouseStart = getTimestamp();
mouseDown = true;
if (AWESOME_MODE) {
particles = [];
ctx.clearRect(0, 0, stageWidth, stageHeight);
}
});
$(window).on('mouseup', function (e) {
var power = getPower();
isExploding = true;
mouseDown = false;
mouseEnd = getTimestamp();
previousPower = power;
generateParticles((random(16) + 30) * power, power / 1.1);
setTimeout(function () {
generateParticles(14 * power, power / 1.4);
}, 100);
setTimeout(function () {
generateParticles(6 * power, power / 2);
}, 200);
setTimeout(function () {
generateParticles(4 * power, power / 2);
}, 400);
});
updateCanvasSize();
$(window).on('resize', updateCanvasSize);
$(function () {
$volcano = $('.volcano-container');
$lava = $volcano.find('.lava');
setTimeout(function () {
$('.toggle').fadeIn();
}, 6000);
$('.toggle').on('click', function () {
AWESOME_MODE = $('#awesome').is(':checked');
});
});
//=============================
// Run it!
//=============================
generateParticles(200, 8);
loop();
</script>
</BODY>
</HTML>