neural-mist-ascending-ye5m/index.html

284 lines
No EOL
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>neural nebula</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a1a;
color: #e0e0e0;
font-family: 'Courier New', monospace;
}
canvas {
display: block;
width: 100vw;
height: 100vh;
}
#attr {
position: absolute;
bottom: 15px;
right: 15px;
font-size: 10px;
opacity: 0.6;
pointer-events: none;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="attr">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();
const params = {
motion: 0.454,
density: 0.487,
complexity: 0.492,
connectedness: 0.514,
lifespan: 0.501,
pulse: { avg: 0.94, min: 0.30, max: 1.70 },
tone: { anger: 0.00, sadness: 0.00, curiosity: 0.70, dryness: 0.80, playfulness: 0.20, tension: 0.00 },
nodes: 63,
branches: 39,
loops: 56,
maxDepth: 17,
thicknessRatio: 1.25,
fractalDim: 1.730,
energy: 208.7
};
class Node {
constructor(x, y) {
this.x = x;
this.y = y;
this.vx = 0;
this.vy = 0;
this.neighbors = [];
this.depth = 0;
this.energy = 200 + Math.random() * 50;
this.lifespan = params.lifespan * 1000 + Math.random() * 2000;
this.createdAt = Date.now();
this.pulse = params.pulse.min + Math.random() * (params.pulse.max - params.pulse.min);
}
connect(other) {
this.neighbors.push(other);
other.neighbors.push(this);
}
update(dt) {
this.energy -= dt * 0.01;
if (Date.now() - this.createdAt > this.lifespan) {
this.energy = 0;
return false;
}
return true;
}
draw() {
const age = Date.now() - this.createdAt;
const t = Math.min(1, age / this.lifespan);
const pulseFactor = this.pulse * (0.9 + Math.sin(Date.now() * 0.001 * 0.5) * 0.1);
const size = 1.5 + (params.thicknessRatio * 1.2) * pulseFactor * t;
const alpha = Math.min(1, this.energy / 100) * (0.7 + t * 0.3);
ctx.beginPath();
ctx.arc(this.x, this.y, size, 0, Math.PI * 2);
ctx.fillStyle = `hsla(180, 40%, 80%, ${alpha})`;
ctx.fill();
this.neighbors.forEach(n => {
const dist = Math.hypot(this.x - n.x, this.y - n.y);
const strength = (n.energy + this.energy) / 200 * pulseFactor * 0.8;
const lineAlpha = Math.min(0.6, strength * 0.5);
if (lineAlpha > 0.05) {
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(n.x, n.y);
ctx.strokeStyle = `hsla(180, 30%, 90%, ${lineAlpha})`;
ctx.lineWidth = 0.5 * pulseFactor * strength;
ctx.stroke();
}
});
}
}
class NeuralNebula {
constructor() {
this.nodes = [];
this.nodesToRemove = [];
this.initNodes();
this.initConnections();
}
initNodes() {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const maxRadius = Math.min(canvas.width, canvas.height) * 0.4;
const nodeCount = params.nodes;
for (let i = 0; i < nodeCount; i++) {
const angle = (i / nodeCount) * Math.PI * 2;
const radius = maxRadius * Math.pow(Math.random(), 0.7);
const x = centerX + Math.cos(angle) * radius + (Math.random() - 0.5) * 200;
const y = centerY + Math.sin(angle) * radius + (Math.random() - 0.5) * 200;
this.nodes.push(new Node(x, y));
}
}
initConnections() {
const connectionMatrix = Array(this.nodes.length).fill().map(() => Array(this.nodes.length).fill(0));
// Create a small-world network with some random long-range connections
this.nodes.forEach((node, i) => {
const neighborCount = Math.floor(params.branches / this.nodes.length) + (Math.random() > 0.5 ? 1 : 0);
for (let j = 0; j < neighborCount; j++) {
let target;
if (Math.random() < params.connectedness && this.nodes.length > 1) {
// Prefer nearby nodes but allow some long-range connections
const sorted = [...this.nodes].sort((a, b) => {
const da = Math.hypot(a.x - node.x, a.y - node.y);
const db = Math.hypot(b.x - node.x, b.y - node.y);
return da - db;
});
const nearby = sorted.slice(0, Math.max(5, Math.floor(this.nodes.length * 0.3)));
target = nearby[Math.floor(Math.random() * nearby.length)];
} else {
target = this.nodes[Math.floor(Math.random() * this.nodes.length)];
}
if (target !== node && !node.neighbors.includes(target) && connectionMatrix[i][this.nodes.indexOf(target)] < 2) {
connectionMatrix[i][this.nodes.indexOf(target)]++;
node.connect(target);
}
}
});
// Create some loops by connecting nodes with similar depths
if (params.loops > 0 && this.nodes.length > 2) {
const depthGroups = this.nodes.reduce((acc, node) => {
const depth = Math.min(5, Math.floor(node.depth));
acc[depth] = acc[depth] || [];
acc[depth].push(node);
return acc;
}, {});
Object.values(depthGroups).forEach(group => {
if (group.length > 1) {
group.forEach(node => {
const other = group[Math.floor(Math.random() * group.length)];
if (node !== other && !node.neighbors.includes(other)) {
node.connect(other);
}
});
}
});
}
}
update(dt) {
// Update nodes and collect dead ones
this.nodes.forEach(node => {
const alive = node.update(dt);
if (!alive) {
this.nodesToRemove.push(node);
}
});
// Remove dead nodes and their connections
if (this.nodesToRemove.length > 0) {
this.nodesToRemove.forEach(node => {
this.nodes = this.nodes.filter(n => n !== node);
this.nodes.forEach(n => n.neighbors = n.neighbors.filter(neighbor => neighbor !== node));
});
this.nodesToRemove = [];
// Reinitialize with new nodes if too many have died
if (this.nodes.length < params.nodes * 0.3) {
this.nodes.forEach(n => n.neighbors = []);
this.initNodes();
this.initConnections();
}
}
// Update node positions with some attraction/repulsion
this.nodes.forEach(node => {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// Attract to center
const dx = centerX - node.x;
const dy = centerY - node.y;
node.vx += dx * 0.0001 * params.motion;
node.vy += dy * 0.0001 * params.motion;
// Repel from other nodes
this.nodes.forEach(other => {
if (node !== other) {
const dist = Math.hypot(node.x - other.x, node.y - other.y);
if (dist < 100) {
const repel = (100 - dist) / 100 * params.motion;
node.vx -= (other.x - node.x) * repel * 0.0002;
node.vy -= (other.y - node.y) * repel * 0.0002;
}
}
});
// Apply velocity
node.x += node.vx;
node.y += node.vy;
node.vx *= 0.95;
node.vy *= 0.95;
// Bound to canvas
node.x = Math.max(0, Math.min(canvas.width, node.x));
node.y = Math.max(0, Math.min(canvas.height, node.y));
});
}
draw() {
// Background glow
ctx.fillStyle = 'rgba(0, 30, 50, 0.05)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Nodes and connections
this.nodes.forEach(node => {
node.draw();
});
}
}
const nebula = new NeuralNebula();
let lastTime = 0;
function animate(time) {
const dt = time - lastTime;
lastTime = time;
nebula.update(dt * 0.001);
ctx.save();
ctx.globalCompositeOperation = 'screen';
nebula.draw();
ctx.restore();
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
</script>
</body>
</html>