live - 60fps 1920 x 1080
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Neon Hexagon Patterns</title>
<style>
html, body {
margin: 0;
padding: 0;
overflow: hidden;
background: #000;
}
/* Make the canvas cover the entire viewport */
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
// Grab the canvas and context
var c = document.getElementById('c');
var ctx = c.getContext('2d');
var w = c.width = window.innerWidth;
var h = c.height = window.innerHeight;
// Configuration options controlling the behaviour of the lines
var opts = {
len: 20,
count: 50,
baseTime: 10,
addedTime: 10,
dieChance: 0.05,
spawnChance: 1,
sparkChance: 0.1,
sparkDist: 10,
sparkSize: 2,
color: 'hsl(hue,100%,light%)',
baseLight: 50,
addedLight: 10, // range: [50-10, 50+10]
shadowToTimePropMult: 6,
baseLightInputMultiplier: 0.01,
addedLightInputMultiplier: 0.02,
cx: w / 2,
cy: h / 2,
repaintAlpha: 0.04,
hueChange: 0.1
};
var tick = 0;
var lines = [];
var dieX = w / 2 / opts.len;
var dieY = h / 2 / opts.len;
var baseRad = Math.PI * 2 / 6;
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, w, h);
/**
* Primary animation loop. Clears the canvas with a semi‑transparent fill,
* spawns new lines as needed, and advances existing lines.
*/
function loop() {
window.requestAnimationFrame(loop);
tick++;
ctx.globalCompositeOperation = 'source-over';
ctx.shadowBlur = 0;
ctx.fillStyle = 'rgba(0,0,0,' + opts.repaintAlpha + ')';
ctx.fillRect(0, 0, w, h);
ctx.globalCompositeOperation = 'lighter';
if (lines.length < opts.count && Math.random() < opts.spawnChance) {
lines.push(new Line());
}
lines.forEach(function(line) {
line.step();
});
}
/**
* Construct a line and initialise its state.
*/
function Line() {
this.reset();
}
Line.prototype.reset = function() {
this.x = 0;
this.y = 0;
this.addedX = 0;
this.addedY = 0;
this.rad = 0;
this.lightInputMultiplier = opts.baseLightInputMultiplier + opts.addedLightInputMultiplier * Math.random();
this.color = opts.color.replace('hue', tick * opts.hueChange);
this.cumulativeTime = 0;
this.beginPhase();
};
/**
* Begin a new movement phase for the line. Chooses a random direction
* and duration. If the line travels too far or randomly dies, it resets.
*/
Line.prototype.beginPhase = function() {
this.x += this.addedX;
this.y += this.addedY;
this.time = 0;
this.targetTime = (opts.baseTime + opts.addedTime * Math.random()) | 0;
this.rad += baseRad * (Math.random() < 0.5 ? 1 : -1);
this.addedX = Math.cos(this.rad);
this.addedY = Math.sin(this.rad);
if (Math.random() < opts.dieChance || this.x > dieX || this.x < -dieX || this.y > dieY || this.y < -dieY) {
this.reset();
}
};
/**
* Advance the line one frame. Draws its current position with a glow.
*/
Line.prototype.step = function() {
this.time++;
this.cumulativeTime++;
if (this.time >= this.targetTime) {
this.beginPhase();
}
var prop = this.time / this.targetTime;
var wave = Math.sin(prop * Math.PI / 2);
var x = this.addedX * wave;
var y = this.addedY * wave;
ctx.shadowBlur = prop * opts.shadowToTimePropMult;
ctx.fillStyle = ctx.shadowColor = this.color.replace('light', opts.baseLight + opts.addedLight * Math.sin(this.cumulativeTime * this.lightInputMultiplier));
ctx.fillRect(opts.cx + (this.x + x) * opts.len, opts.cy + (this.y + y) * opts.len, 2, 2);
// occasional sparks
if (Math.random() < opts.sparkChance) {
ctx.fillRect(
opts.cx + (this.x + x) * opts.len + Math.random() * opts.sparkDist * (Math.random() < 0.5 ? 1 : -1) - opts.sparkSize / 2,
opts.cy + (this.y + y) * opts.len + Math.random() * opts.sparkDist * (Math.random() < 0.5 ? 1 : -1) - opts.sparkSize / 2,
opts.sparkSize,
opts.sparkSize
);
}
};
loop();
// Resize handler to keep canvas full‑screen
window.addEventListener('resize', function() {
w = c.width = window.innerWidth;
h = c.height = window.innerHeight;
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, w, h);
opts.cx = w / 2;
opts.cy = h / 2;
dieX = w / 2 / opts.len;
dieY = h / 2 / opts.len;
});
</script>
</body>
</html> About this animation
Glowing hexagonal grid pattern with neon effects.
Under the hood
SVG Polygon Grids
The background is structured using interlocking
SVG nodes mapped to the exact angles of hexagons. A looping script slowly pulses the stroke and fill-opacity properties to make the cyberpunk facade breathe.