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; } | |
| } |