<div class="info">move mouse (mobile version coming soon)</div>
body, html {
margin: 0; padding: 0;
background: black;
overflow: hidden;
}
.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;
}
// color version with z-sorting: https://codepen.io/ZevanRosser/pen/zBpbzK
// @TODO fix for non-babel and use touchevents for phone
let canvas = document.createElement('canvas'),
c = canvas.getContext('2d'),
NUM = 30,
clocks = [],
color = '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) => 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 ];
},
drawCircle2d(points) {
points.forEach(function(seg) {
c.beginPath();
c.moveTo(seg[0], seg[1]);
c.bezierCurveTo(seg[2], seg[3], seg[4], seg[5], seg[6], seg[7]);
c.strokeStyle = color;
c.stroke();
});
},
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() * 100 - 50,
r = 10 + Math.random() * 30,
smallRad = r - r * 0.3,
smallerRad = r - r * 0.5,
theta = Math.random() * 2 * Math.PI,
slowTheta = Math.random() * 2 * Math.PI;
return () => {
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);
theta += 0.1;
c.strokeStyle = color;
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;
this.drawCircle3d(x, y, z, r);
};
},
draw() {
c.save();
c.fillStyle = 'rgba(0, 0, 0, 0.2)';
c.fillRect(0, 0, canvas.width, canvas.height);
c.translate(canvas.width / 2, canvas.height / 2);
c.scale(2, 2);
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.