<div class="info">move mouse (mobile version coming soon)</div>
body, html {
margin: 0; padding: 0;
background: black;
overflow: hidden;
background: rgba(132, 217, 176, 1);
}
.info {
position: absolute;
left: 0; bottom: 0;
z-index: 99;
color: white;
padding: 20px;
font-size: 0.8em;
font-family: "Helvetica Neue", sans-serif;
background: transparent;
}
// @TODO fix for non-babel and use touchevents for phone
let canvas = document.createElement('canvas'),
c = canvas.getContext('2d'),
NUM = 25,
clocks = [],
handColor = 'rgba(255, 255, 255, 0.9)',
bgColor = 'rgba(132, 217, 176, 0.5)',
fillColor = 'rgba(255, 199, 115, 0.7)',
shadeColor = 'rgba(21, 15, 156, 0.05)',
strokeColor = 'rgba(255, 255, 255, 0.2)',
// 2d stuff
mouseX = 0, mouseY = 0,
k = ( 4 / 3 ) * (Math.sqrt(2) - 1), // kappa
// 3d stuff
rotX = 0, rotY = 0,
perspective = 500,
depth,
currX, currY;
document.body.appendChild(canvas);
let nonsenseClocks = {
// sort of based on:
// http://stackoverflow.com/questions/30341871/how-to-create-approximate-circle-with-b%C3%A9zier-curve-html-5-and-add-transition-to
circlePoints(x, y, r) {
let addXy = (v, i) => i % 2 ? v + y : v + x;
return [
[ 0, -r, k * r, -r , r, -k * r, r, 0 ],
[ r, 0, r, k * r, k * r ,r , 0, r ],
[ 0, r, -k * r ,r , -r , k * r , -r ,0 ],
[ -r, 0, -r, -k * r, -k * r , -r, 0, -r ]
].map((seg) => {
return seg.map(addXy);
});
},
// learned something like this at Andries Odendaal's www.wireframe.co.za back in the day
point3d(x, y, z) {
let cosX = Math.cos(rotX),
cosY = Math.cos(rotY),
sinX = Math.sin(rotX),
sinY = Math.sin(rotY),
posX, posY, posZ;
posZ = z * cosX - x * sinX,
posX = z * sinX + x * cosX,
posY = y * cosY - posZ * sinY,
posZ = y * sinY + posZ * cosY;
depth = 1 / (posZ / perspective + 1);
currX = posX * depth;
currY = posY * depth;
return [ currX, currY, depth ];
},
drawCircle2d(points) {
c.strokeStyle = strokeColor;
c.lineWidth = 4;
c.shadowColor = shadeColor;
c.shadowBlur = 5;
c.shadowOffsetX = 10;
c.shadowOffsetY = 0;
c.beginPath();
points.forEach(function(seg, i) {
if (i === 0) {
c.moveTo(seg[0], seg[1]);
}
c.bezierCurveTo(seg[2], seg[3], seg[4], seg[5], seg[6], seg[7]);
});
c.closePath()
c.stroke();
c.fill();
},
drawCircle3d(x, y, z, r) {
let points = this.circlePoints(x, y, r),
points3d = [];
for (let i = 0; i < points.length; i++) {
let segs = points[i],
segs3d = [];
for (let j = 0; j < segs.length - 1; j += 2) {
let x = segs[j],
y = segs[j + 1],
ptn = this.point3d(x, y, z);
segs3d.push(ptn[0], ptn[1]);
}
points3d.push(segs3d);
}
this.drawCircle2d(points3d);
},
create(x, y, time) {
let z = Math.random() * 200 - 100,
r = 5 + Math.random() * 20,
smallRad = r - r * 0.3,
smallerRad = r - r * 0.5,
theta = Math.random() * 2 * Math.PI,
slowTheta = Math.random() * 2 * Math.PI,
l = Math.floor(Math.random() * 70),
rc = 255,
gc = 199 + l,
bc = 115 + l;
const clock = () => {
let xp = x + smallRad * Math.cos(theta),
yp = y + smallRad * Math.sin(theta),
zero = nonsenseClocks.point3d(x, y, z),
pnt = nonsenseClocks.point3d(xp, yp, z);
clock.depth = zero[2];
theta += 0.1;
c.fillStyle = `rgba(${rc}, ${gc}, ${bc}, 0.7)`;
this.drawCircle3d(x, y, z, r);
c.strokeStyle = handColor;
c.lineWidth = 1;
c.lineJoin = 'round';
c.beginPath()
c.moveTo(pnt[0], pnt[1]);
c.lineTo(zero[0], zero[1]);
// c.stroke();
xp = x + smallerRad * Math.cos(slowTheta);
yp = y + smallerRad * Math.sin(slowTheta);
pnt = this.point3d(xp, yp, z);
// c.beginPath();
// c.moveTo(zero[0], zero[1]);
c.lineTo(pnt[0], pnt[1]);
c.stroke();
slowTheta += 0.05;
};
return clock;
},
draw() {
c.save();
c.fillStyle = bgColor;
c.fillRect(0, 0, canvas.width, canvas.height);
c.translate(canvas.width / 2, canvas.height / 2);
let s = (window.innerWidth + window.innerHeight) / 800;
c.scale(s, s);
clocks.sort((a, b) => a.depth - b.depth);
clocks.forEach((clock) => clock());
c.restore();
},
resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
this.draw();
return this;
},
loop() {
rotX += ((mouseX * Math.PI / 180) - rotX) / 8;
rotY += ((mouseY * Math.PI / 180) - rotY) / 8;
nonsenseClocks.draw();
requestAnimationFrame(nonsenseClocks.loop);
return this;
}
};
Array(NUM).fill(0).forEach(() => {
let theta = Math.random() * Math.PI * 2,
radius = Math.random() * 200,
x = radius * Math.cos(theta),
y = radius * Math.sin(theta);
clocks.push(nonsenseClocks.create(x, y, theta));
});
window.addEventListener('resize', () => nonsenseClocks.resize());
nonsenseClocks.resize().loop();
// touch todo
document.addEventListener('mousemove', (e) => {
mouseX = e.pageX;
mouseY = e.pageY;
});
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.