Requires a browser that can handle CSS filter (or -webkit-filter).
A Pen by Matt Popovich on CodePen.
Requires a browser that can handle CSS filter (or -webkit-filter).
A Pen by Matt Popovich on CodePen.
<canvas id="world"></canvas> | |
<canvas class="grain"></canvas> | |
<div class="hawkins"> | |
<div class="el"> | |
<div class="part eyelids"></div> | |
<div class="part arm"></div> | |
<div class="part hand"></div> | |
<div class="part eye-problems"></div> | |
<div class="part blood"></div> | |
</div> | |
</div> |
// Canvas grain by Renārs Vilnis: | |
// https://codepen.io/renarsvilnis/pen/YWKRvE | |
// Falling confetti by Linmiao Xu | |
// https://codepen.io/linrock/pen/Amdhr?editors=1010 | |
'use strict'; | |
console.clear(); | |
class Grain { | |
constructor (el) { | |
/** | |
* Options | |
* Increase the pattern size if visible pattern | |
*/ | |
this.patternSize = 200; | |
this.patternScaleX = 1000; | |
this.patternScaleY = 1000; | |
this.patternRefreshInterval = 5; | |
this.patternAlpha = 18; | |
/** | |
* Create canvas | |
*/ | |
this.canvas = el; | |
this.ctx = this.canvas.getContext('2d'); | |
this.ctx.scale(this.patternScaleX, this.patternScaleY); | |
/** | |
* Create a canvas that will be used to generate grain and used as a | |
* pattern on the main canvas. | |
*/ | |
this.patternCanvas = document.createElement('canvas'); | |
this.patternCanvas.width = this.patternSize; | |
this.patternCanvas.height = this.patternSize; | |
this.patternCtx = this.patternCanvas.getContext('2d'); | |
this.patternData = this.patternCtx.createImageData(this.patternSize, this.patternSize); | |
this.patternPixelDataLength = this.patternSize * this.patternSize * 4; // rgba = 4 | |
/** | |
* Prebind prototype function, so later its easier to user | |
*/ | |
this.resize = this.resize.bind(this); | |
this.loop = this.loop.bind(this); | |
this.frame = 0; | |
window.addEventListener('resize', this.resize); | |
this.resize(); | |
window.requestAnimationFrame(this.loop); | |
} | |
resize () { | |
this.canvas.width = window.innerWidth * devicePixelRatio; | |
this.canvas.height = window.innerHeight * devicePixelRatio; | |
} | |
update () { | |
const {patternPixelDataLength, patternData, patternAlpha, patternCtx} = this; | |
// put a random shade of gray into every pixel of the pattern | |
for (let i = 0; i < patternPixelDataLength; i += 4) { | |
// const value = (Math.random() * 255) | 0; | |
const value = Math.random() * 255; | |
patternData.data[i] = value; | |
patternData.data[i + 1] = value; | |
patternData.data[i + 2] = value; | |
patternData.data[i + 3] = patternAlpha; | |
} | |
patternCtx.putImageData(patternData, 0, 0); | |
} | |
draw () { | |
const {ctx, patternCanvas, canvas, viewHeight} = this; | |
const {width, height} = canvas; | |
// clear canvas | |
ctx.clearRect(0, 0, width, height); | |
// fill the canvas using the pattern | |
ctx.fillStyle = ctx.createPattern(patternCanvas, 'repeat'); | |
ctx.fillRect(0, 0, width, height); | |
} | |
loop () { | |
// only update grain every n frames | |
const shouldDraw = ++this.frame % this.patternRefreshInterval === 0; | |
if (shouldDraw) { | |
this.update(); | |
this.draw(); | |
} | |
window.requestAnimationFrame(this.loop); | |
} | |
} | |
/** | |
* Initiate Grain | |
*/ | |
const el = document.querySelector('.grain'); | |
const grain = new Grain(el); | |
(function() { | |
var COLORS, Confetti, NUM_CONFETTI, PI_2, canvas, confetti, context, drawCircle, i, range, resizeWindow, xpos; | |
NUM_CONFETTI = 350; | |
COLORS = [[85, 71, 106], [174, 61, 99], [219, 56, 83], [244, 92, 68], [248, 182, 70]]; | |
PI_2 = 2 * Math.PI; | |
canvas = document.getElementById("world"); | |
context = canvas.getContext("2d"); | |
window.w = 0; | |
window.h = 0; | |
resizeWindow = function() { | |
window.w = canvas.width = window.innerWidth; | |
return window.h = canvas.height = window.innerHeight; | |
}; | |
window.addEventListener('resize', resizeWindow, false); | |
window.onload = function() { | |
return setTimeout(resizeWindow, 0); | |
}; | |
range = function(a, b) { | |
return (b - a) * Math.random() + a; | |
}; | |
drawCircle = function(x, y, r, style) { | |
context.beginPath(); | |
context.arc(x, y, r, 0, PI_2, false); | |
context.fillStyle = style; | |
return context.fill(); | |
}; | |
xpos = 0.5; | |
document.onmousemove = function(e) { | |
return xpos = e.pageX / w; | |
}; | |
window.requestAnimationFrame = (function() { | |
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { | |
return window.setTimeout(callback, 1000 / 60); | |
}; | |
})(); | |
Confetti = (function() { | |
function Confetti() { | |
this.style = COLORS[~~range(0, 5)]; | |
this.rgb = "rgba(" + this.style[0] + "," + this.style[1] + "," + this.style[2]; | |
this.r = ~~range(2, 6); | |
this.r2 = 2 * this.r; | |
this.replace(); | |
} | |
Confetti.prototype.replace = function() { | |
this.opacity = 0; | |
this.dop = 0.03 * range(1, 4); | |
this.x = range(-this.r2, w - this.r2); | |
this.y = range(-20, h - this.r2); | |
this.xmax = w - this.r; | |
this.ymax = h - this.r; | |
this.vx = range(0, 2) + 8 * xpos - 5; | |
return this.vy = 0.7 * this.r + range(-1, 1); | |
}; | |
Confetti.prototype.draw = function() { | |
var ref; | |
this.x += this.vx; | |
this.y += this.vy; | |
this.opacity += this.dop; | |
if (this.opacity > 1) { | |
this.opacity = 1; | |
this.dop *= -1; | |
} | |
if (this.opacity < 0 || this.y > this.ymax) { | |
this.replace(); | |
} | |
if (!((0 < (ref = this.x) && ref < this.xmax))) { | |
this.x = (this.x + this.xmax) % this.xmax; | |
} | |
return drawCircle(~~this.x, ~~this.y, this.r, this.rgb + "," + this.opacity + ")"); | |
}; | |
return Confetti; | |
})(); | |
confetti = (function() { | |
var j, ref, results; | |
results = []; | |
for (i = j = 1, ref = NUM_CONFETTI; 1 <= ref ? j <= ref : j >= ref; i = 1 <= ref ? ++j : --j) { | |
results.push(new Confetti); | |
} | |
return results; | |
})(); | |
window.step = function() { | |
var c, j, len, results; | |
requestAnimationFrame(step); | |
context.clearRect(0, 0, w, h); | |
results = []; | |
for (j = 0, len = confetti.length; j < len; j++) { | |
c = confetti[j]; | |
results.push(c.draw()); | |
} | |
return results; | |
}; | |
step(); | |
}).call(this); |
$anim-length: 10s; | |
html, body { height: 100%; } | |
body { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
background-color: black; | |
overflow: hidden; | |
} | |
#world { | |
position: absolute; | |
z-index: 7; | |
width: 100%; | |
height: 100%; | |
top: 0; | |
left: 0; | |
opacity: 0; | |
filter: brightness(1000%); | |
-webkit-filter: brightness(1000%); | |
animation: upside-rain $anim-length linear infinite; | |
} | |
@keyframes upside-rain { | |
0% { opacity: 0; } | |
30% { opacity: 0; } | |
32% { opacity: 0.075; } | |
50% { opacity: 0.075; } | |
52% { opacity: 0; } | |
100% { opacity: 0; } | |
} | |
.grain { | |
position: absolute; | |
z-index: 9; | |
left: 0; | |
top: 0; | |
width: 100%; | |
height: 100%; | |
} | |
.hawkins { | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
width: 700px; | |
height: 500px; | |
background-image: url(https://res.cloudinary.com/dxscrtoxq/image/upload/v1468782962/posterback_vrnptz.png); | |
background-size: 650px; | |
background-repeat: no-repeat; | |
background-position: center; | |
animation: upside-down $anim-length linear infinite; | |
} | |
@keyframes upside-down { | |
0% { filter: none; -webkit-filter: none; } | |
30% { filter: none; -webkit-filter: none; } | |
31% { filter: brightness(400%); -webkit-filter: brightness(400%); } | |
32% { filter: brightness(400%); -webkit-filter: brightness(400%); } | |
33% { | |
filter: sepia(100%) hue-rotate(180deg) saturate(450%) contrast(115%) brightness(75%); | |
-webkit-filter: sepia(100%) hue-rotate(180deg) saturate(450%) contrast(115%) brightness(75%); | |
} | |
50% { | |
filter: sepia(100%) hue-rotate(180deg) saturate(450%) contrast(115%) brightness(75%); | |
-webkit-filter: sepia(100%) hue-rotate(180deg) saturate(450%) contrast(115%) brightness(75%); | |
} | |
51% { filter: brightness(400%); -webkit-filter: brightness(400%); } | |
52% { filter: brightness(400%); -webkit-filter: brightness(400%); } | |
53% { filter: none; -webkit-filter: none; } | |
100% { filter: none; -webkit-filter: none; } | |
} | |
.el { | |
position: relative; | |
margin-left: 65px; | |
width: 500px; | |
height: 500px; | |
background-image: url(https://res.cloudinary.com/dxscrtoxq/image/upload/v1468782960/eleven_eyeca0.png); | |
background-size: 400px; | |
background-repeat: no-repeat; | |
background-position: center; | |
animation: el-shake 5s linear infinite; | |
} | |
@keyframes el-shake { | |
0% { transform: translate(0px, 0px); } | |
15% { transform: translate(1px, 0px); } | |
30% { transform: translate(0px, 1px); } | |
45% { transform: translate(-1px, 1px); } | |
60% { transform: translate(-1px, 0px); } | |
75% { transform: translate(0px, 0px); } | |
85% { transform: translate(0px, -1px); } | |
100% { transform: translate(0px, 0px); } | |
} | |
.part { | |
position: absolute; | |
background-repeat: no-repeat; | |
background-position: center; | |
background-size: 100%; | |
} | |
.eyelids { | |
z-index: 5; | |
opacity: 0; | |
top: 163px; | |
left: 119px; | |
width: 117px; | |
height: 100px; | |
background-image: url(https://res.cloudinary.com/dxscrtoxq/image/upload/v1468782959/eyelids_s12six.png); | |
animation: blink 6.5s ease-out infinite; | |
} | |
@keyframes blink { | |
0% { opacity: 0 } | |
20% { opacity: 0 } | |
21% { opacity: 0.8 } | |
21.5% { opacity: 0.8 } | |
23% { opacity: 0 } | |
60% { opacity: 0 } | |
61% { opacity: 0.95 } | |
61.5% { opacity: 0.95 } | |
63% { opacity: 0 } | |
70% { opacity: 0 } | |
71% { opacity: 0.85 } | |
71.5% { opacity: 0.85 } | |
73% { opacity: 0 } | |
100% { opacity: 0 } | |
} | |
.arm { | |
top: 232px; | |
left: 233px; | |
width: 150px; | |
height: 300px; | |
background-image: url(https://res.cloudinary.com/dxscrtoxq/image/upload/v1468782959/arm_iwjvzv.png); | |
animation: arm-shake 5s ease-out infinite; | |
} | |
@keyframes arm-shake { | |
0% { transform: translate(0px, 1px); } | |
15% { transform: translate(1px, 1px); } | |
30% { transform: translate(0px, 1px); } | |
45% { transform: translate(0px, 1px); } | |
60% { transform: translate(1px, 0px); } | |
75% { transform: translate(1px, 0px); } | |
85% { transform: translate(1px, 1px); } | |
100% { transform: translate(0px, 1px); } | |
} | |
.hand { | |
top: 197px; | |
left: 181px; | |
width: 282px; | |
height: 300px; | |
background-image: url(https://res.cloudinary.com/dxscrtoxq/image/upload/v1468782959/hand_kuy5dz.png); | |
animation: hand-shake 8s ease-out infinite; | |
} | |
@keyframes hand-shake { | |
0% { transform: translate(1px, -1px) scale(1.01); } | |
10% { transform: translate(-1px, -1px) scale(1.02); } | |
30% { transform: translate(1px, 1px) scale(1.05); } | |
35% { transform: translate(-1px, -1px) scale(1); } | |
45% { transform: translate(0px, 1px) scale(1.0175); } | |
60% { transform: translate(-1px, -1px) scale(1.01); } | |
85% { transform: translate(1px, 1px) scale(1.04); } | |
100% { transform: translate(1px, -1px) scale(1.01); } | |
} | |
.eye-problems { | |
top: 72px; | |
left: 107px; | |
width: 142px; | |
height: 300px; | |
opacity: 0.7; | |
background-image: url(https://res.cloudinary.com/dxscrtoxq/image/upload/v1468782958/eye-problems_y1f6ne.png); | |
animation: side-effects $anim-length ease-out infinite; | |
} | |
@keyframes side-effects { | |
0% { opacity: 0; } | |
30% { opacity: 0; } | |
50% { opacity: .8; } | |
90% { opacity: 0; } | |
100% { opacity: 0; } | |
} | |
.blood { | |
top: 225px; | |
left: 180px; | |
width: 20px; | |
height: 100px; | |
opacity: 1; | |
background-image: url(https://res.cloudinary.com/dxscrtoxq/image/upload/v1468782958/blood_rnujxa.png); | |
animation: drip $anim-length ease-out infinite; | |
} | |
@keyframes drip { | |
0% { opacity: 0; } | |
30% { opacity: 0; } | |
50% { opacity: 1; } | |
80% { opacity: 1; } | |
100% { opacity: 0; } | |
} |