birth: monochrome veins pulse
This commit is contained in:
parent
9e0ee156b8
commit
6dd458eafd
1 changed files with 101 additions and 0 deletions
101
index.html
Normal file
101
index.html
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Pulsing Fractal Veins</title>
|
||||||
|
<style>
|
||||||
|
body { margin: 0; overflow: hidden; background: #0a0a0a; }
|
||||||
|
canvas { display: block; }
|
||||||
|
#attribution { position: absolute; bottom: 10px; right: 10px; color: #333; font-family: monospace; font-size: 10px; }
|
||||||
|
</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 resize() {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', resize);
|
||||||
|
resize();
|
||||||
|
|
||||||
|
// Cellular automata parameters (dryness=0.90, complexity=0.50)
|
||||||
|
const cellSize = 5;
|
||||||
|
const cols = Math.floor(canvas.width / cellSize);
|
||||||
|
const rows = Math.floor(canvas.height / cellSize);
|
||||||
|
|
||||||
|
// Initialize grid with binary states (0 or 1)
|
||||||
|
let grid = Array.from({length: rows}, () => Array.from({length: cols}, () => Math.random() > 0.8 ? 1 : 0));
|
||||||
|
|
||||||
|
// Rule: Conway's Game of Life with slight variation to create pulsating patterns
|
||||||
|
function updateGrid() {
|
||||||
|
const newGrid = grid.map(arr => [...arr]);
|
||||||
|
|
||||||
|
for (let y = 0; y < rows; y++) {
|
||||||
|
for (let x = 0; x < cols; x++) {
|
||||||
|
let alive = grid[y][x];
|
||||||
|
let neighbors = 0;
|
||||||
|
|
||||||
|
// Count live neighbors with wrap-around
|
||||||
|
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;
|
||||||
|
neighbors += grid[ny][nx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cellular automata rules - variation to create organic growth
|
||||||
|
if (alive) {
|
||||||
|
newGrid[y][x] = neighbors >= 2 && neighbors <= 5 ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
newGrid[y][x] = neighbors === 3 || neighbors === 6 ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grid = newGrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drawing with dryness tone (monochrome)
|
||||||
|
function draw() {
|
||||||
|
// Fade previous frame with low alpha for persistence
|
||||||
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
// Calculate intensity based on cellular automata state
|
||||||
|
ctx.fillStyle = `rgba(255, 255, 255, 0.8)`;
|
||||||
|
|
||||||
|
for (let y = 0; y < rows; y++) {
|
||||||
|
for (let x = 0; x < cols; x++) {
|
||||||
|
if (grid[y][x]) {
|
||||||
|
const px = x * cellSize;
|
||||||
|
const py = y * cellSize;
|
||||||
|
ctx.fillRect(px, py, cellSize * 0.8, cellSize * 0.8);
|
||||||
|
|
||||||
|
// Add slight pulsing effect based on global pulse
|
||||||
|
const pulse = 1.06 + Math.sin(Date.now() * 0.001 * (0.9 + Math.random() * 0.3)) * 0.1;
|
||||||
|
ctx.fillStyle = `rgba(255, 255, 255, ${0.6 * pulse})`;
|
||||||
|
ctx.fillRect(px + cellSize * 0.1, py + cellSize * 0.1,
|
||||||
|
cellSize * 0.6 * pulse, cellSize * 0.6 * pulse);
|
||||||
|
ctx.fillStyle = `rgba(255, 255, 255, 0.8)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
updateGrid();
|
||||||
|
draw();
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start animation
|
||||||
|
animate();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Reference in a new issue