birth: Dissolving Grid of Echoes
This commit is contained in:
parent
9bdec65053
commit
16f3b41c82
1 changed files with 145 additions and 0 deletions
145
index.html
Normal file
145
index.html
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Dissolving Grid</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #0a0a0a;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
canvas {
|
||||
display: block;
|
||||
}
|
||||
#attribution {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
mix-blend-mode: difference;
|
||||
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 resize() {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
}
|
||||
window.addEventListener('resize', resize);
|
||||
resize();
|
||||
|
||||
// Reaction-diffusion parameters (Gray-Scott model)
|
||||
const params = {
|
||||
feed: 0.055,
|
||||
kill: 0.062,
|
||||
timeStep: 1.0,
|
||||
diffusionRateA: 1.0,
|
||||
diffusionRateB: 0.5,
|
||||
gridSize: 4,
|
||||
colorMode: 0 // 0 = monochrome (dryness=0.9)
|
||||
};
|
||||
|
||||
const gridWidth = Math.ceil(canvas.width / params.gridSize);
|
||||
const gridHeight = Math.ceil(canvas.height / params.gridSize);
|
||||
|
||||
let currentGrid = new Array(gridWidth * gridHeight).fill(0);
|
||||
let nextGrid = new Array(gridWidth * gridHeight).fill(0);
|
||||
|
||||
// Initialize with random values
|
||||
for (let i = 0; i < currentGrid.length; i++) {
|
||||
currentGrid[i] = Math.random() * 0.1;
|
||||
}
|
||||
|
||||
// Color palette (monochrome due to dryness=0.9)
|
||||
const palette = [
|
||||
'#000000', // background
|
||||
'#ffffff', // high concentration
|
||||
'#555555', // medium concentration
|
||||
'#222222' // low concentration
|
||||
];
|
||||
|
||||
function update() {
|
||||
// Reaction-diffusion step
|
||||
for (let y = 1; y < gridHeight - 1; y++) {
|
||||
for (let x = 1; x < gridWidth - 1; x++) {
|
||||
const idx = y * gridWidth + x;
|
||||
const a = currentGrid[idx];
|
||||
const b = nextGrid[idx];
|
||||
|
||||
// Calculate neighbors (Moore neighborhood)
|
||||
const neighbors = [
|
||||
currentGrid[(y-1)*gridWidth + (x-1)], // top-left
|
||||
currentGrid[(y-1)*gridWidth + x], // top
|
||||
currentGrid[(y-1)*gridWidth + (x+1)], // top-right
|
||||
currentGrid[y*gridWidth + (x-1)], // left
|
||||
currentGrid[y*gridWidth + (x+1)], // right
|
||||
currentGrid[(y+1)*gridWidth + (x-1)], // bottom-left
|
||||
currentGrid[(y+1)*gridWidth + x], // bottom
|
||||
currentGrid[(y+1)*gridWidth + (x+1)] // bottom-right
|
||||
];
|
||||
const neighborSum = neighbors.reduce((a, b) => a + b, 0);
|
||||
|
||||
// Reaction-diffusion equations
|
||||
const f = params.feed;
|
||||
const k = params.kill;
|
||||
const dA = params.diffusionRateA;
|
||||
const dB = params.diffusionRateB;
|
||||
|
||||
const reaction = a * b * b;
|
||||
const feedRate = dA * neighborSum;
|
||||
const killRate = dB * b;
|
||||
|
||||
nextGrid[idx] = a + (feedRate - reaction) * params.timeStep;
|
||||
nextGrid[idx] = Math.max(0, Math.min(1, nextGrid[idx]));
|
||||
|
||||
nextGrid[idx] += (reaction - killRate) * params.timeStep;
|
||||
nextGrid[idx] = Math.max(0, Math.min(1, nextGrid[idx]));
|
||||
}
|
||||
}
|
||||
|
||||
// Simple swap (no need to deep copy)
|
||||
[currentGrid, nextGrid] = [nextGrid, currentGrid];
|
||||
|
||||
// Clear canvas with semi-transparent overlay
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Draw cells
|
||||
const cellSize = params.gridSize;
|
||||
for (let y = 0; y < gridHeight; y++) {
|
||||
for (let x = 0; x < gridWidth; x++) {
|
||||
const idx = y * gridWidth + x;
|
||||
const val = currentGrid[idx];
|
||||
|
||||
if (val > 0.01) {
|
||||
const intensity = Math.min(1, val * 2);
|
||||
const color = palette[colorMode];
|
||||
ctx.fillStyle = color;
|
||||
ctx.globalAlpha = intensity * 0.8;
|
||||
ctx.beginPath();
|
||||
ctx.rect(x * cellSize, y * cellSize, cellSize, cellSize);
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.globalAlpha = 1.0;
|
||||
|
||||
requestAnimationFrame(update);
|
||||
}
|
||||
|
||||
update();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue