birth: Fractured Voronoi Currents

This commit is contained in:
motd_admin 2026-08-13 18:21:23 +00:00
parent 910c37844c
commit 984c2a100c

211
index.html Normal file
View file

@ -0,0 +1,211 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fractal Voronoi Dreams</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a0a;
font-family: 'Courier New', monospace;
}
canvas {
display: block;
width: 100vw;
height: 100vh;
}
#attribution {
position: absolute;
bottom: 10px;
right: 10px;
color: #4a4a4a;
font-size: 10px;
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();
// Parameters derived from the abstract values
const params = {
motion: 0.527,
density: 0.455,
complexity: 0.521,
connectedness: 0.452,
lifespan: 0.582,
survivingNodes: 54,
branchCount: 50,
loops: 227,
maxDepth: 13,
thicknessRatio: 1.5,
fractalDimension: 1.251,
finalEnergy: 301.8,
pulse: { avg: 0.48, min: 0.3, max: 1.75 },
tone: { anger: 0.0, sadness: 0.0, curiosity: 0.7, dryness: 0.9, playfulness: 0.1, tension: 0.0 }
};
// Color palette based on tone
const colors = {
bg: '#0a0a0a',
primary: `hsl(180, ${params.tone.dryness * 20 + 10}%, ${params.tone.curiosity * 10 + 20}%)`,
secondary: `hsl(120, ${params.tone.dryness * 30 + 5}%, ${params.tone.dryness * 40 + 30}%)`,
accent: `hsl(300, ${params.tone.playfulness * 50 + 10}%, ${params.tone.playfulness * 20 + 50}%)`
};
// Voronoi cell data
let sites = [];
let diagram = { cells: [], edges: [] };
let time = 0;
function initVoronoi() {
// Generate sites based on density and complexity
const siteCount = Math.floor(params.density * 300 + 20);
for (let i = 0; i < siteCount; i++) {
sites.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * params.motion * 2,
vy: (Math.random() - 0.5) * params.motion * 2,
size: params.complexity * 3 + 1,
persistence: 0.8 + Math.random() * 0.2
});
}
}
function updateVoronoi() {
// Move sites
sites.forEach(site => {
site.x += site.vx * params.pulse.avg;
site.y += site.vy * params.pulse.avg;
// Boundary check
if (site.x < 0) {
site.x = canvas.width;
site.vx *= -1;
} else if (site.x > canvas.width) {
site.x = 0;
site.vx *= -1;
}
if (site.y < 0) {
site.y = canvas.height;
site.vy *= -1;
} else if (site.y > canvas.height) {
site.y = 0;
site.vy *= -1;
}
});
// Generate Voronoi diagram (simplified)
diagram = generateVoronoi(sites);
// Update complexity by adding/removing edges
if (Math.random() < params.complexity * 0.01 && diagram.edges.length < 500) {
diagram.edges.push(createRandomEdge());
}
}
function generateVoronoi(sites) {
// Simplified Voronoi generation using distance
const cells = sites.map((site, i) => ({
site: site,
edges: [],
neighbors: [],
index: i
}));
const edges = [];
// Calculate all possible edges
for (let i = 0; i < cells.length; i++) {
for (let j = i + 1; j < cells.length; j++) {
const dx = cells[j].site.x - cells[i].site.x;
const dy = cells[j].site.y - cells[i].site.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300 * params.complexity) {
edges.push({
cell1: i,
cell2: j,
distance: distance,
thickness: params.thicknessRatio * 2 + Math.random() * params.thicknessRatio,
color: colors.primary
});
}
}
}
return { cells, edges };
}
function createRandomEdge() {
const i = Math.floor(Math.random() * sites.length);
const j = Math.floor(Math.random() * sites.length);
const dx = sites[j].x - sites[i].x;
const dy = sites[j].y - sites[i].y;
const distance = Math.sqrt(dx * dx + dy * dy);
return {
cell1: i,
cell2: j,
distance: distance,
thickness: params.thicknessRatio * 2 + Math.random() * params.thicknessRatio,
color: `hsl(180, 50%, ${params.tone.dryness * 60 + 30}%)`
};
}
function drawVoronoi() {
// Clear with semi-transparent background for trails
ctx.fillStyle = 'rgba(10, 10, 10, 0.05)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw edges with fading based on distance
diagram.edges.forEach(edge => {
const cell1 = diagram.cells[edge.cell1];
const cell2 = diagram.cells[edge.cell2];
// Fade color based on distance and lifespan
const alpha = 1 - (edge.distance / 300);
ctx.strokeStyle = edge.color.replace(')', `, ${alpha * params.lifespan})`);
ctx.lineWidth = edge.thickness * params.complexity;
ctx.beginPath();
ctx.moveTo(cell1.site.x, cell1.site.y);
ctx.lineTo(cell2.site.x, cell2.site.y);
ctx.stroke();
});
// Draw sites as points
sites.forEach(site => {
ctx.fillStyle = `rgba(150, 255, 255, ${params.tone.curiosity})`;
ctx.beginPath();
ctx.arc(site.x, site.y, params.density * 2, 0, Math.PI * 2);
ctx.fill();
});
}
function animate() {
updateVoronoi();
drawVoronoi();
time += 0.01;
requestAnimationFrame(animate);
}
initVoronoi();
animate();
</script>
</body>
</html>