birth: Pulsing Recursive Convergence
This commit is contained in:
parent
2840f4752d
commit
c00a77e93f
1 changed files with 164 additions and 0 deletions
164
index.html
Normal file
164
index.html
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Recursive Convergence</title>
|
||||
<style>
|
||||
body { margin: 0; overflow: hidden; background: #0a0a0a; }
|
||||
canvas { display: block; }
|
||||
#info { position: absolute; bottom: 10px; right: 10px; color: #555; font-family: monospace; font-size: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c"></canvas>
|
||||
<div id="info">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();
|
||||
|
||||
// Fractal configuration derived from parameters
|
||||
const config = {
|
||||
motion: 0.486,
|
||||
density: 0.512,
|
||||
complexity: 0.435,
|
||||
connectedness: 0.528,
|
||||
lifespan: 0.437,
|
||||
loops: 270,
|
||||
fractalDepth: 18 * config.complexity,
|
||||
thickness: 1.25 * config.connectedness,
|
||||
energy: 296.6 * (1 - config.lifespan),
|
||||
pulseRate: 1 / (0.54 * 1000),
|
||||
minSize: 0.5,
|
||||
maxSize: 1.75,
|
||||
hue: 180,
|
||||
saturation: 80 * (1 - config.dryness),
|
||||
brightness: 60 + config.energy * 0.1,
|
||||
nodes: 55,
|
||||
branches: 47,
|
||||
branchRatio: 0.7
|
||||
};
|
||||
|
||||
// Fractal nodes with recursive growth
|
||||
let nodes = [];
|
||||
let branches = [];
|
||||
let frames = 0;
|
||||
|
||||
class FractalNode {
|
||||
constructor(x, y, size, depth, parent) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.size = size;
|
||||
this.depth = depth;
|
||||
this.parent = parent;
|
||||
this.children = [];
|
||||
this.life = 0;
|
||||
this.energy = config.energy * (config.lifespan + Math.random() * (1 - config.lifespan));
|
||||
this.hue = config.hue + Math.sin(depth * 0.1) * 30;
|
||||
this.pulse = 1 + Math.sin(frames * config.pulseRate) * config.motion * 0.7;
|
||||
this.alpha = 0.3 + this.energy / 400;
|
||||
}
|
||||
|
||||
grow() {
|
||||
if (this.depth >= config.fractalDepth) return;
|
||||
|
||||
const numChildren = Math.max(1, Math.floor(config.branches * config.branchRatio * config.density));
|
||||
for (let i = 0; i < numChildren; i++) {
|
||||
const angle = Math.PI * 2 * i / numChildren;
|
||||
const distance = this.size * (0.7 + Math.sin(this.depth * 0.3) * 0.1);
|
||||
const childSize = this.size * config.complexity * 0.5;
|
||||
|
||||
if (childSize < config.minSize) break;
|
||||
|
||||
const child = new FractalNode(
|
||||
this.x + Math.cos(angle) * distance,
|
||||
this.y + Math.sin(angle) * distance,
|
||||
childSize,
|
||||
this.depth + 1,
|
||||
this
|
||||
);
|
||||
this.children.push(child);
|
||||
branches.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
this.life++;
|
||||
this.size *= 1 + config.motion * 0.002;
|
||||
this.alpha = this.alpha * 0.97 + 0.3 * (this.energy / 400);
|
||||
this.pulse = 1 + Math.sin(frames * config.pulseRate + this.x * 0.01) * config.motion * 0.5;
|
||||
|
||||
this.children.forEach(child => child.update());
|
||||
}
|
||||
|
||||
draw() {
|
||||
const pulseSize = this.size * this.pulse;
|
||||
const s = Math.max(0.5, pulseSize * config.thickness);
|
||||
const a = Math.min(1, this.alpha);
|
||||
|
||||
// Draw branch to parent
|
||||
if (this.parent) {
|
||||
ctx.strokeStyle = `hsla(${this.hue}, ${config.saturation}%, ${config.brightness}%, ${a * 0.7})`;
|
||||
ctx.lineWidth = s * config.thickness;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.x, this.y);
|
||||
ctx.lineTo(this.parent.x, this.parent.y);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Draw node
|
||||
ctx.fillStyle = `hsla(${this.hue}, ${config.saturation}%, ${config.brightness}%, ${a})`;
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.x, this.y, s, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
this.children.forEach(child => child.draw());
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
// Create initial nodes in a fractal pattern
|
||||
const centerX = canvas.width / 2;
|
||||
const centerY = canvas.height / 2;
|
||||
const initialSize = 100 * config.density;
|
||||
|
||||
for (let i = 0; i < config.nodes; i++) {
|
||||
const angle = Math.PI * 2 * i / config.nodes;
|
||||
const distance = 30 + Math.random() * 50;
|
||||
nodes.push(new FractalNode(
|
||||
centerX + Math.cos(angle) * distance,
|
||||
centerY + Math.sin(angle) * distance,
|
||||
initialSize * (0.7 + Math.random() * 0.3),
|
||||
0
|
||||
));
|
||||
branches.push(nodes[i]);
|
||||
}
|
||||
|
||||
// Grow fractal branches
|
||||
nodes.forEach(node => node.grow());
|
||||
}
|
||||
|
||||
function animate() {
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
branches.forEach(branch => branch.update());
|
||||
branches.forEach(branch => branch.draw());
|
||||
|
||||
frames++;
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
init();
|
||||
animate();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue