fractal-drift-through-disor.../index.html

146 lines
No EOL
4.4 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fractal Drift</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a0a;
font-family: 'Courier New', monospace;
color: #ccc;
display: flex;
justify-content: center;
align-items: flex-end;
height: 100vh;
}
canvas {
display: block;
}
#attribution {
position: absolute;
bottom: 20px;
font-size: 10px;
color: #555;
pointer-events: none;
}
</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 attractor = {
a: 0.2,
b: 0.9,
c: 1.5,
d: 0.3,
scale: 100,
offsetX: 0.5,
offsetY: 0.5,
maxPoints: 50000,
points: [],
history: []
};
// Initialize with motion parameter
attractor.a = 0.2 + Math.random() * 0.3;
attractor.b = 0.7 + Math.random() * 0.4;
attractor.c = 1.2 + Math.random() * 0.6;
attractor.d = 0.1 + Math.random() * 0.2;
function generateAttractorPoints() {
let x = 0.1;
let y = 0.1;
for (let i = 0; i < attractor.maxPoints; i++) {
const x1 = Math.sin(y * attractor.b - attractor.c);
const y1 = Math.sin(x1 * attractor.a) * -1;
x = x1;
y = y1;
const px = (x + attractor.offsetX) * attractor.scale;
const py = (y + attractor.offsetY) * attractor.scale;
attractor.points.push({x: px, y: py});
// Store every 10th point for drawing trails
if (i % 5 === 0) {
attractor.history.push({x: px, y: py});
if (attractor.history.length > 200) {
attractor.history.shift();
}
}
}
}
generateAttractorPoints();
// Pulse animation
let pulse = 1.0;
const targetPulse = 1.0 + (Math.random() * 0.6 - 0.3);
const pulseSpeed = 0.005 + Math.random() * 0.01;
function drawAttractor() {
// Pulse effect
pulse += (targetPulse - pulse) * pulseSpeed;
ctx.lineWidth = 1.5 * pulse;
ctx.strokeStyle = `rgba(200, 200, 200, ${0.5 + pulse * 0.5})`;
// Draw all points
ctx.beginPath();
for (let i = 0; i < attractor.points.length; i++) {
const p = attractor.points[i];
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.x, p.y);
}
ctx.stroke();
// Draw fading trail
ctx.lineWidth = 1 * pulse;
for (let i = 0; i < attractor.history.length; i++) {
const h = attractor.history[i];
const alpha = i / attractor.history.length;
ctx.strokeStyle = `rgba(180, 180, 180, ${alpha * 0.7})`;
ctx.beginPath();
ctx.moveTo(h.x, h.y);
ctx.lineTo(h.x, h.y);
ctx.stroke();
}
}
function animate() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.15)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Add slight rotation based on motion parameter
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(0.001 * Math.sin(Date.now() * 0.001));
ctx.translate(-centerX, -centerY);
drawAttractor();
ctx.restore();
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>