birth: Static Voronoi Pulses

This commit is contained in:
motd_admin 2026-06-12 21:47:16 +00:00
parent 5728b8707b
commit 2cfda52d31

161
index.html Normal file
View file

@ -0,0 +1,161 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Voronoi Organism</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a1a;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: 'Courier New', monospace;
color: #e0e0e0;
}
canvas {
display: block;
}
#attribution {
position: absolute;
bottom: 20px;
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();
// Voronoi parameters derived from abstract specs
const params = {
motion: 0.5,
density: 0.5,
complexity: 0.5,
connectedness: 0.5,
lifespan: 0.5,
pulse: {avg: 1.08, min: 1.05, max: 1.10},
tone: {dryness: 0.80, curiosity: 0.10},
color: '#c0c0c0'
};
// Voronoi cells with dynamic movement
class Cell {
constructor(x, y, size) {
this.x = x;
this.y = y;
this.size = size;
this.vx = (Math.random() - 0.5) * params.motion * 2;
this.vy = (Math.random() - 0.5) * params.motion * 2;
this.life = Math.random() * params.lifespan;
this.maxLife = this.life;
this.connections = [];
this.thickness = 1;
}
update(voronoi) {
// Pulse effect
const pulseFactor = params.pulse.avg;
this.x += this.vx * pulseFactor;
this.y += this.vy * pulseFactor;
// 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;
// Connections based on connectedness
if (Math.random() < params.connectedness && voronoi.cells.length > 0) {
const other = voronoi.cells[Math.floor(Math.random() * voronoi.cells.length)];
if (other !== this && !this.connections.includes(other)) {
this.connections.push(other);
}
}
this.life -= 0.001;
}
draw(ctx) {
// Draw cell
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = params.color;
ctx.fill();
// Draw connections
if (params.connectedness > 0) {
ctx.strokeStyle = params.color;
ctx.lineWidth = this.thickness;
this.connections.forEach(conn => {
ctx.beginPath();
ctx.moveTo(this.x, this.y);
ctx.lineTo(conn.x, conn.y);
ctx.stroke();
});
}
}
}
class Voronoi {
constructor() {
this.cells = [];
this.initCells();
}
initCells() {
const count = Math.floor(params.density * 200 + 50);
for (let i = 0; i < count; i++) {
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
const size = 2 + Math.random() * 8;
this.cells.push(new Cell(x, y, size));
}
}
update() {
this.cells.forEach(cell => cell.update(this));
// Remove dead cells
this.cells = this.cells.filter(cell => cell.life > 0);
// Add new cells based on density
if (Math.random() < 0.01 && this.cells.length < 500) {
this.initCells();
}
}
draw() {
this.cells.forEach(cell => cell.draw(ctx));
}
}
let voronoi = new Voronoi();
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'rgba(0, 5, 15, 0.1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
voronoi.update();
voronoi.draw();
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>