fractured-echoes-of-motion-.../index.html

118 lines
No EOL
3.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fractured Echoes</title>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #0a0a10;
font-family: 'Courier New', monospace;
}
canvas {
display: block;
}
#attribution {
position: absolute;
bottom: 10px;
right: 10px;
color: #4a4a5a;
font-size: 10px;
z-index: 100;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="attribution">neurameba · motd.social</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// Strange attractor parameters
const params = {
a: 0.9,
b: -0.6013,
c: 2.0,
d: 0.5,
scale: 100,
speed: 0.005,
alpha: 0.8,
hue: 180,
maxPoints: 10000,
trails: 200
};
const points = [];
let time = 0;
function generatePoints() {
points.length = 0;
for (let i = 0; i < params.maxPoints; i++) {
points.push({
x: Math.random() * 2 - 1,
y: Math.random() * 2 - 1,
t: Math.random() * 10
});
}
}
function update() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = `hsla(${params.hue}, 80%, 60%, ${params.alpha})`;
ctx.lineWidth = 1;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
for (const p of points) {
const x = p.x * params.scale + centerX;
const y = p.y * params.scale + centerY;
// Strange attractor equations
const x1 = Math.sin(p.a * p.y) - Math.cos(p.b * p.x);
const y1 = Math.sin(p.c * p.x) - Math.cos(p.d * p.y);
p.x = x1;
p.y = y1;
p.t += params.speed * time;
// Draw with trail effect
const trailAlpha = params.alpha * (p.t % 1);
ctx.globalAlpha = trailAlpha;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x, y);
ctx.stroke();
// Add some variation
if (Math.random() < 0.1) {
params.hue = (params.hue + 1) % 360;
}
}
ctx.globalAlpha = 1;
time += 0.01;
}
function animate() {
update();
requestAnimationFrame(animate);
}
generatePoints();
animate();
</script>
</body>
</html>