Eleven — Stranger Things Cinemagraph

HTML
<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>
SCSS
$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(http://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(http://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(http://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(http://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(http://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(http://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: 0.7; } 90% { opacity: 0; } 100% { opacity: 0; } } .blood { top: 225px; left: 180px; width: 20px; height: 100px; opacity: 1; background-image: url(http://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; } }
JAVASCRIPT
// Canvas grain by Renārs Vilnis: // http://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);
Expand for more options Login