fractal-dust-dispersing-n32a/index.html

107 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>chaos bloom</title>
<style>
body, html {
margin: 0;
padding: 0;
overflow: hidden;
background: #0a0a0a;
height: 100%;
}
canvas {
display: block;
}
.attribution {
position: fixed;
bottom: 10px;
right: 10px;
color: #444;
font-family: monospace;
font-size: 10px;
pointer-events: none;
z-index: 100;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div class="attribution">neurameba · motd.social</div>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Strange attractor parameters
const points = [];
const maxPoints = 10000;
const a = 4.5 + 1.4 * (Math.random() * 2 - 1);
const b = 0.2 + 0.1 * (Math.random() * 2 - 1);
const c = 5.8 + 1.2 * (Math.random() * 2 - 1);
let x = 0.1, y = 0.1;
// Stroke style based on tone parameters
const dryness = 0.8;
const playfulness = 0.1;
const hue = 180 + (playfulness * 60);
const sat = 15 + (dryness * 85);
const light = 70 + (1 - dryness) * 30;
function update() {
// Motion influence
const motion = 0.5;
const steps = Math.floor(1 + motion * 20);
for (let i = 0; i < steps; i++) {
if (points.length < maxPoints) {
points.push({x: x * canvas.width/2 + canvas.width/2,
y: y * canvas.height/2 + canvas.height/2,
size: 1 + Math.random() * 1.5,
alpha: 0.7 + Math.random() * 0.3});
// Strange attractor equations
const xn = Math.sin(a * y) - Math.cos(b * x);
const yn = Math.sin(x) - Math.cos(c * y);
x = xn;
y = yn;
}
}
// Fading trail effect
ctx.fillStyle = `rgba(0, 0, 0, 0.05)`;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw points
points.forEach((p, i) => {
const age = i / points.length;
const size = p.size * (1 - age * 0.7);
const alpha = p.alpha * (1 - age * 0.5);
ctx.fillStyle = `hsla(${hue}, ${sat}%, ${light}%, ${alpha})`;
ctx.beginPath();
ctx.arc(p.x, p.y, size, 0, Math.PI * 2);
ctx.fill();
});
// Cull old points
while (points.length > maxPoints) {
points.shift();
}
}
function animate() {
update();
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>