birth: Pulsing Gray Veins
This commit is contained in:
parent
92d3526554
commit
e6be44035a
1 changed files with 167 additions and 0 deletions
167
index.html
Normal file
167
index.html
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Cellular Swarm</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #0a0a0a;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
}
|
||||||
|
#info {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 0;
|
||||||
|
color: #4a4a4a;
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
background: rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
</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();
|
||||||
|
|
||||||
|
// Parameters from prompt
|
||||||
|
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.1 },
|
||||||
|
tone: { anger: 0.0, sadness: 0.0, curiosity: 0.1, dryness: 0.9, playfulness: 0.0, tension: 0.0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fixed random seed for deterministic behavior
|
||||||
|
Math.seed = (Math.random() * 1e9) | 0;
|
||||||
|
Math.rand = (min, max) => {
|
||||||
|
Math.seed = (Math.seed * 9301 + 49297) % 233280;
|
||||||
|
return min + (Math.seed / 233280) * (max - min);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cell grid
|
||||||
|
const cellSize = 4;
|
||||||
|
const cols = Math.floor(canvas.width / cellSize);
|
||||||
|
const rows = Math.floor(canvas.height / cellSize);
|
||||||
|
const grid = Array.from({ length: rows }, () =>
|
||||||
|
Array.from({ length: cols }, () => false)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Initialize with density
|
||||||
|
for (let y = 0; y < rows; y++) {
|
||||||
|
for (let x = 0; x < cols; x++) {
|
||||||
|
grid[y][x] = Math.rand(0, 1) < params.density * 0.5 + 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rule set ( Conway's Game of Life variants )
|
||||||
|
function rule(x, y) {
|
||||||
|
let neighbors = 0;
|
||||||
|
for (let dy = -1; dy <= 1; dy++) {
|
||||||
|
for (let dx = -1; dx <= 1; dx++) {
|
||||||
|
if (dx === 0 && dy === 0) continue;
|
||||||
|
const nx = (x + dx + cols) % cols;
|
||||||
|
const ny = (y + dy + rows) % rows;
|
||||||
|
if (grid[ny][nx]) neighbors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Colors
|
||||||
|
const bg = '#0a0a0a';
|
||||||
|
const fg = params.tone.dryness > 0.7 ? '#cccccc' : '#11ffaa';
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
ctx.fillStyle = bg;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
// Adjust pulse
|
||||||
|
const pulse = params.pulse.avg * (1 + 0.2 * Math.sin(Date.now() * 0.002));
|
||||||
|
|
||||||
|
// Update grid
|
||||||
|
const newGrid = Array.from({ length: rows }, () => Array(cols).fill(false));
|
||||||
|
|
||||||
|
for (let y = 0; y < rows; y++) {
|
||||||
|
for (let x = 0; x < cols; x++) {
|
||||||
|
const n = rule(x, y);
|
||||||
|
const isAlive = grid[y][x];
|
||||||
|
|
||||||
|
// High complexity leads to more varied rules
|
||||||
|
if (params.complexity > 0.4) {
|
||||||
|
if (isAlive) {
|
||||||
|
newGrid[y][x] = n >= 2 && n <= 4;
|
||||||
|
} else {
|
||||||
|
newGrid[y][x] = n === 3 || n === 6;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Standard Game of Life
|
||||||
|
newGrid[y][x] = (isAlive && (n === 2 || n === 3)) || (!isAlive && n === 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.length = 0;
|
||||||
|
for (let y = 0; y < rows; y++) {
|
||||||
|
grid.push([...newGrid[y]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect cells with lines based on connectedness
|
||||||
|
ctx.strokeStyle = fg;
|
||||||
|
ctx.lineWidth = cellSize * 0.3 * pulse;
|
||||||
|
|
||||||
|
for (let y = 0; y < rows; y++) {
|
||||||
|
for (let x = 0; x < cols; x++) {
|
||||||
|
if (grid[y][x]) {
|
||||||
|
const neighbors = rule(x, y);
|
||||||
|
if (neighbors >= 3 || params.connectedness > 0.7) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x * cellSize, y * cellSize);
|
||||||
|
|
||||||
|
// Find random neighbor to connect to
|
||||||
|
const nx = (x + Math.rand(-3, 4) + cols) % cols;
|
||||||
|
const ny = (y + Math.rand(-3, 4) + rows) % rows;
|
||||||
|
|
||||||
|
if (grid[ny][nx]) {
|
||||||
|
ctx.lineTo(nx * cellSize, ny * cellSize);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pulse effect
|
||||||
|
if (Math.rand(0, 1) < 0.1 * params.motion) {
|
||||||
|
const x = Math.rand(0, cols) * cellSize;
|
||||||
|
const y = Math.rand(0, rows) * cellSize;
|
||||||
|
ctx.fillStyle = fg;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(x, y, cellSize * 2 * pulse, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
draw();
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
animate();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Reference in a new issue