JSFiddle - React, Tailwind, and code Playground
by Christian Sonne
HTML
<canvas id="c"></canvas>
<canvas id="d"></canvas>
<div id="robot"></div>
CSS
* {
margin: 0;
padding: 0;
}
canvas {
background: black;
transform-origin: 0 0;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
#c {
transform: translate(49px, 122px) scale(0.09);
}
#d {
transform: translate(149px, 122px) scale(0.09);
}
#robot {
position: absolute;
top: 0;
left: 0;
background: url(https://i.imgur.com/6X40vYY.png) top left no-repeat;
height: 605px;
width: 806px;
z-index: 1;
}
JavaScript
let S = c.height = c.width = d.height = d.width = 19 * 30;
let s = S / 2;
let ctx = c.getContext("2d");
let ctx2 = d.getContext("2d");
let nPixels = 32;
let D = S / nPixels;
let r = Math.floor(D / 3);
lidTargets = [];
lidTarget = null;
lid = 0;
let mouse = {x: 0, y: 0};
window.addEventListener("mousemove", function(e) {
let angle = Math.atan2(s - e.clientY, s - e.clientX);
let d = dist(e.clientX, e.clientY, s, s);
d = clamp(d, 0, 2 * s / 3);
mouse.x = s - Math.cos(angle) * d;
mouse.y = s - Math.sin(angle) * d;
}, false);
window.addEventListener("click", function() {
lidTargets.push(S);
lidTargets.push(0);
}, false);
ctx.fillStyle = "white";
function clamp(v, ll, ul) {
if (typeof ll === "undefined") ll = 0;
if (typeof ul === "undefined") ul = 1;
return Math.min(ul, Math.max(ll, v));
}
function dist(x1, y1, x2, y2) {
return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2);
}
function grade(v, ul, ll) {
return clamp(-v / (ll - ul) + 1 + ul / (ll - ul));
}
function draw() {
if ((typeof lidTarget === "undefined" && lidTargets.length) || Math.abs(lidTarget - lid) <= 20) {
lidTarget = lidTargets.shift();
}
if (typeof lidTarget !== "undefined") {
lid += Math.sign(lidTarget - lid) * 65;
}
ctx.clearRect(0, 0, S, S);
for (let y = 0; y < nPixels; y++) {
let Y = (y + 0.5) * D;
for (let x = 0; x < nPixels; x++) {
let X = (x + 0.5) * D;
let d1 = dist(s, s, X, Y);
let alpha1 = grade(d1, s - r, s);
if (lid >= Y) {
ctx.globalAlpha = alpha1;
ctx.save();
ctx.fillStyle = "#76A2CC";
} else {
let d2 = dist(mouse.x, mouse.y, X, Y);
let alpha2 = grade(d2, s / 3, s / 3 - r);
ctx.globalAlpha = Math.min(alpha1, alpha2);
}
ctx.beginPath();
ctx.arc(X, Y, r, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
}
ctx2.clearRect(0, 0, S, S);
ctx2.drawImage(c, 0, 0);
window.requestAnimationFrame(draw);
}
draw();