JSFiddle - React, Tailwind, and code Playground
CSS
body { background: #800; margin: 0 }
JavaScript
var a = document.createElement("canvas");
var TAU = Math.PI * 2;
document.body.appendChild(a);
a.width = window.innerWidth;
a.height = window.innerHeight;
var c = a.getContext('2d');
var test = [0, 0, 1, 0];
var cameraR = Math.min(a.width, a.height) / 2;
var cameraZ = 0;
var cameraD = 10;
var cameraL = 0.25 * cameraR;
var cameraZF = 0.1;
var cx = a.width / 2;
var cy = a.height / 2;
function d3(z) {
q = 80;
return cameraR - p3(q, z);
}
function p3(q, z) {
return z * (q - q * z * 0.1)
}
function renderRow(z, i) {
var outerRadius = d3(z);
var innerRadius = d3(z + 1);
if (innerRadius <= 10) return;
c.fillStyle = i % 2 ? "#404" : "#606";
c.beginPath();
c.arc(0, 0, outerRadius, 0, TAU, false);
c.arc(0, 0, innerRadius, 0, TAU, true);
c.fill();
}
var path = [[0, 0]];
var pitch = 0;
var tick = Date.now();
var d = 0;
var s = 0;
setInterval(function () {
var delta = (Date.now() - tick) / 1000;
tick = Date.now();
c.save();
var cx = a.width / 2 + s * 32;
var cy = a.height / 2 - s * 32;
// c.globalAlpha = 0.25 + Math.abs(0.5 * s);
pitch += delta * 3 * s;
path.push([cameraZ+2, pitch]);
if(path.length > 40) path.shift();
d += delta;
s = Math.sin((d % 2 / 2) * TAU);
c.translate(cx, cy);
//c.rotate(d);
cameraZ += delta * 2;
for (var i = -1; i < 20; i++) {
renderRow(i + cameraZ % 6.05, i);
}
c.beginPath();
c.strokeStyle = "#fff";
var cl = ["#0fa", "#0a8", "#fa0", "#f80", "#f00", "#a00"];
for(var k = 0; k < 3; k++) {
c.rotate(2);
for(var i = path.length - 1; i > 0; i--) {
var p = path[i];
var x = 0;
var r = d3(p[0] - cameraZ);
var x = Math.cos(p[1]) * r;
var y = Math.sin(p[1]) * r;
c.globalAlpha = 1.0;
c.fillStyle = cl[k * 2 + (i % 2)];
c.fillRect(x, y, r*0.2,...