whispering-data-tendrils-dr9w/index.html

178 lines
No EOL
6.1 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Neurameba Network</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a0a;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
canvas {
display: block;
}
#attribution {
position: fixed;
bottom: 10px;
right: 10px;
color: #333;
font-family: monospace;
font-size: 10px;
opacity: 0.5;
}
</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();
// Parameters
const params = {
motion: 0.5,
density: 0.5,
complexity: 0.5,
connectedness: 0.5,
lifespan: 0.5,
pulse: { avg: 1.1, min: 1.0, max: 1.2 },
tone: { anger: 0, sadness: 0, curiosity: 0.1, dryness: 0.9, playfulness: 0, tension: 0 }
};
// Node and connection system
const nodes = [];
const connections = [];
const maxNodes = 100;
const nodeSize = 2 + params.density * 3;
const connectionThickness = 0.5 + params.connectedness * 1.5;
const baseColor = `hsl(0, 0%, ${80 - params.tone.dryness * 40}%)`;
const activeColor = `hsl(${200 + params.tone.curiosity * 60}, ${30 + params.tone.curiosity * 40}%, ${70}%)`;
class Node {
constructor() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.vx = (Math.random() - 0.5) * params.motion * 2;
this.vy = (Math.random() - 0.5) * params.motion * 2;
this.size = nodeSize;
this.lifetime = 0;
this.maxLifetime = 100 + Math.random() * 200;
this.connections = [];
this.pulse = params.pulse.avg + (Math.random() * 2 - 1) * (params.pulse.max - params.pulse.min) / 2;
}
update() {
this.x += this.vx;
this.y += this.vy;
// Boundary check
if (this.x < 0) { this.x = canvas.width; }
if (this.x > canvas.width) { this.x = 0; }
if (this.y < 0) { this.y = canvas.height; }
if (this.y > canvas.height) { this.y = 0; }
this.lifetime++;
if (this.lifetime > this.maxLifetime) {
this.lifetime = 0;
this.maxLifetime = 100 + Math.random() * 200;
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
}
}
draw() {
const age = this.lifetime / this.maxLifetime;
const pulseScale = 1 + Math.sin(Date.now() * 0.001 * this.pulse) * 0.1;
const size = this.size * pulseScale;
const alpha = Math.min(1, age * 2);
ctx.beginPath();
ctx.arc(this.x, this.y, size, 0, Math.PI * 2);
ctx.fillStyle = age > 0.5 ? activeColor : baseColor;
ctx.globalAlpha = alpha;
ctx.fill();
ctx.globalAlpha = 1;
}
}
function createNodes() {
nodes.length = 0;
connections.length = 0;
const count = Math.floor(maxNodes * params.density);
for (let i = 0; i < count; i++) {
nodes.push(new Node());
}
}
function connectNodes() {
connections.length = 0;
const maxConnections = Math.floor(params.connectedness * 5);
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
const possibleConnections = nodes.filter(n => n !== node);
for (let j = 0; j < Math.min(maxConnections, possibleConnections.length); j++) {
const other = possibleConnections[Math.floor(Math.random() * possibleConnections.length)];
if (!node.connections.includes(other) && !other.connections.includes(node) &&
Math.random() < 0.3 + params.connectedness * 0.5) {
node.connections.push(other);
other.connections.push(node);
connections.push({ from: node, to: other });
}
}
}
}
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
nodes.forEach(node => node.update());
connections.forEach(conn => {
const dx = conn.to.x - conn.from.x;
const dy = conn.to.y - conn.from.y;
const dist = Math.sqrt(dx * dx + dy * dy);
const maxDist = 150 - params.complexity * 100;
if (dist < maxDist) {
const alpha = Math.min(0.5, maxDist / dist * 0.1);
ctx.beginPath();
ctx.moveTo(conn.from.x, conn.from.y);
ctx.lineTo(conn.to.x, conn.to.y);
ctx.strokeStyle = baseColor;
ctx.lineWidth = connectionThickness * (1 - dist / maxDist);
ctx.globalAlpha = alpha;
ctx.stroke();
ctx.globalAlpha = 1;
}
});
nodes.forEach(node => node.draw());
}
function animate() {
update();
requestAnimationFrame(animate);
}
createNodes();
connectNodes();
animate();
</script>
</body>
</html>