live - 60fps 1920 x 1080
<!DOCTYPE html>
<html>
<head>
<title>Plasma Tunnel</title>
<style>
:root {
--bg-color: #000008;
--glow-1: #7c3aed;
--glow-2: #22d3ee;
}
* { margin: 0; padding: 0; }
body { height: 100vh; background: var(--bg-color); overflow: hidden; }
canvas { display: block; width: 100vw; height: 100vh; image-rendering: pixelated; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const cv = document.getElementById('c');
const ctx = cv.getContext('2d');
ctx.imageSmoothingEnabled = false;
const css = getComputedStyle(document.documentElement);
function hex(h) {
h = (h || '').trim().replace('#', '');
if (h.length === 3) h = h.split('').map(c => c + c).join('');
const n = parseInt(h, 16); return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
}
const g1 = hex(css.getPropertyValue('--glow-1') || '#7c3aed');
const g2 = hex(css.getPropertyValue('--glow-2') || '#22d3ee');
const SCALE = 4;
let lw, lh, img, buf, rad, ang;
function build() {
cv.width = Math.ceil(innerWidth / SCALE);
cv.height = Math.ceil(innerHeight / SCALE);
lw = cv.width; lh = cv.height;
img = ctx.createImageData(lw, lh); buf = img.data;
rad = new Float32Array(lw * lh);
ang = new Float32Array(lw * lh);
const cx = lw / 2, cy = lh / 2;
for (let y = 0; y < lh; y++) {
for (let x = 0; x < lw; x++) {
const dx = x - cx, dy = y - cy;
const idx = y * lw + x;
rad[idx] = Math.sqrt(dx * dx + dy * dy);
ang[idx] = Math.atan2(dy, dx);
}
}
}
addEventListener('resize', build);
build();
function step(t) {
for (let i = 0; i < rad.length; i++) {
const dist = rad[i];
const d = 34 / (dist + 1.2); // depth coord — grows toward the centre
const a = ang[i];
// tunnel wall: concentric rings scrolling toward the viewer + angular flutes
const rings = Math.sin(d * 3.2 - t * 3);
const flutes = Math.sin(a * 8 + d * 0.6 + t * 0.4);
let tex = 0.5 + 0.5 * rings * flutes;
const light = Math.min(1, dist * 0.013); // lit walls at the edge, dark vanishing point
let s = (0.22 + 0.78 * tex) * light;
if (s < 0) s = 0; else if (s > 1) s = 1;
const mix = 0.5 + 0.5 * Math.sin(d * 2 + a * 3 - t * 1.5);
const j = i * 4;
buf[j] = (g1[0] + (g2[0] - g1[0]) * mix) * s | 0;
buf[j + 1] = (g1[1] + (g2[1] - g1[1]) * mix) * s | 0;
buf[j + 2] = (g1[2] + (g2[2] - g1[2]) * mix) * s | 0;
buf[j + 3] = 255;
}
ctx.putImageData(img, 0, 0);
}
if (matchMedia('(prefers-reduced-motion: reduce)').matches) {
step(1.0);
} else {
let t = 0;
(function loop() { t += 0.03; step(t); requestAnimationFrame(loop); })();
}
</script>
</body>
</html> About this animation
A hypnotic demoscene tunnel — spiralling plasma flutes rush inward toward a dark vanishing point in an endless psychedelic zoom.