birth: Fractured Hive Pulse

This commit is contained in:
motd_admin 2026-05-03 01:47:21 +00:00
parent 3cef71498f
commit 9d9ff93aac

221
index.html Normal file
View file

@ -0,0 +1,221 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Neurameba Fractal Pulse</title>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #0a0a0a;
color: #ddd;
font-family: 'Courier New', monospace;
display: flex;
flex-direction: column;
height: 100vh;
}
canvas {
display: block;
flex: 1;
}
.attribution {
text-align: right;
padding: 8px 16px;
font-size: 10px;
opacity: 0.6;
background: rgba(0,0,0,0.3);
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div class="attribution">neurameba · motd.social</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Set canvas to full window size
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// Parameters derived from input
const params = {
motion: 0.473,
density: 0.477,
complexity: 0.494,
connectedness: 0.494,
lifespan: 0.489,
pulse: { avg: 0.40, min: 0.30, max: 1.95 },
tone: { anger: 0.00, sadness: 0.00, curiosity: 0.10, dryness: 0.90, playfulness: 0.00, tension: 0.00 },
metrics: {
survivingNodes: 146,
branchCount: 131,
loops: 1228,
maxDepth: 27,
thicknessRatio: 1.50,
fractalDimension: 1.331,
finalEnergy: 909.5
}
};
// Derived values
const pointCount = Math.floor(100 + params.metrics.survivingNodes * 2 * params.density);
const voronoiMultiplier = 0.8 + params.complexity * 0.4;
const edgeLife = 200 + params.metrics.maxDepth * 5;
const lineThickness = 1.2 + params.metrics.thicknessRatio * 0.8;
const pulseRange = params.pulse.max - params.pulse.min;
// Generate random points with some clustering
const points = [];
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const maxRadius = Math.min(canvas.width, canvas.height) * 0.45;
for (let i = 0; i < pointCount; i++) {
const angle = Math.random() * Math.PI * 2;
const radius = Math.random() * maxRadius;
const x = centerX + Math.cos(angle) * radius * (0.7 + Math.random() * 0.6);
const y = centerY + Math.sin(angle) * radius * (0.7 + Math.random() * 0.6);
// Add slight movement based on motion parameter
const vx = (Math.random() - 0.5) * params.motion * 2;
const vy = (Math.random() - 0.5) * params.motion * 2;
points.push({
x, y,
vx, vy,
baseX: x, baseY: y,
energy: 0.5 + Math.random() * 0.5,
lifespan: 50 + Math.random() * 100
});
}
// Create voronoi diagram using relative points
function createVoronoi(p) {
return points.map(pt => ({
x: pt.x + p * pt.vx * 2,
y: pt.y + p * pt.vy * 2
}));
}
// Generate edges between nearby points (based on complexity/connectedness)
function generateEdges(voronoiPoints, t) {
const edges = [];
const maxDist = 80 * (0.5 + params.connectedness * 0.8);
const influence = params.motion * 2;
for (let i = 0; i < voronoiPoints.length; i++) {
for (let j = i + 1; j < voronoiPoints.length; j++) {
const dx = voronoiPoints[j].x - voronoiPoints[i].x;
const dy = voronoiPoints[j].y - voronoiPoints[i].y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < maxDist) {
const strength = 1 - dist / maxDist;
const age = (t + (i + j) * 0.1) % edgeLife;
const opacity = Math.min(1, strength * (1 - age / edgeLife));
edges.push({
i, j,
length: dist,
strength,
age,
maxAge: edgeLife,
pulse: Math.sin(t * 0.002 + (i + j) * 0.1) * 0.5 + 0.5
});
}
}
}
return edges;
}
// Animation state
let t = 0;
const trails = [];
function animate() {
// Clear with slight trail
ctx.fillStyle = 'rgba(10, 10, 10, 0.05)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Calculate pulse effect
const pulse = params.pulse.avg + Math.sin(t * 0.003) * pulseRange * 0.3;
// Create voronoi points with motion
const voronoiPoints = createVoronoi(pulse * 0.15);
// Generate edges
const edges = generateEdges(voronoiPoints, t);
// Draw edges with pulse-based thickness
edges.forEach(edge => {
const pulseFactor = edge.pulse < 0.5 ? edge.pulse * 2 : 1 - (edge.pulse - 0.5) * 2;
const thickness = lineThickness * (0.8 + pulseFactor * 0.4);
const opacity = 0.6 + params.metrics.finalEnergy / 2000;
const alpha = opacity * (1 - edge.age / edge.maxAge) * (0.3 + params.density * 0.7);
ctx.lineWidth = thickness;
ctx.globalAlpha = alpha;
ctx.beginPath();
ctx.moveTo(voronoiPoints[edge.i].x, voronoiPoints[edge.i].y);
ctx.lineTo(voronoiPoints[edge.j].x, voronoiPoints[edge.j].y);
ctx.strokeStyle = `hsl(0, 0%, ${60 + Math.sin(t * 0.001 + edge.i) * 10}%)`;
ctx.stroke();
});
// Draw points with some pulsing
points.forEach((pt, i) => {
const size = 1.5 + Math.sin(t * 0.002 + i) * 0.5;
ctx.globalAlpha = pt.energy * (0.7 + pulse * 0.3);
ctx.beginPath();
ctx.arc(voronoiPoints[i].x, voronoiPoints[i].y, size, 0, Math.PI * 2);
ctx.fillStyle = `hsl(0, 0%, ${30 + Math.sin(t * 0.001 + i * 0.3) * 10}%)`;
ctx.fill();
});
t += 1;
// Add to trails occasionally
if (t % 15 === 0 && trails.length < 200) {
trails.push({
points: [...voronoiPoints],
alpha: 0.1,
age: 0
});
}
// Draw trails
trails.forEach((trail, idx) => {
trail.age++;
trail.alpha = 0.1 * (1 - trail.age / 50);
if (trail.alpha > 0) {
trail.points.forEach((pt, i) => {
ctx.globalAlpha = trail.alpha * (0.5 + Math.sin(t * 0.002 + i) * 0.3);
ctx.beginPath();
ctx.arc(pt.x, pt.y, 1, 0, Math.PI * 2);
ctx.fillStyle = `hsl(0, 0%, ${50 + Math.sin(t * 0.001 + i * 0.3) * 5}%)`;
ctx.fill();
});
} else {
trails.splice(idx, 1);
}
});
// Reset opacity
ctx.globalAlpha = 1;
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>