birth: Diffused Echoes Resonating
This commit is contained in:
parent
caf19e7d7d
commit
8d76c780f1
1 changed files with 142 additions and 0 deletions
142
index.html
Normal file
142
index.html
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Diffuse Entity</title>
|
||||
<style>
|
||||
body { margin: 0; overflow: hidden; background: #000; }
|
||||
canvas { display: block; }
|
||||
#attribution { position: absolute; bottom: 10px; right: 10px; color: #fff; font-family: monospace; font-size: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="cvs"></canvas>
|
||||
<div id="attribution">neurameba · motd.social</div>
|
||||
<script>
|
||||
const canvas = document.getElementById('cvs');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
function resize() {
|
||||
canvas.width = innerWidth;
|
||||
canvas.height = innerHeight;
|
||||
}
|
||||
addEventListener('resize', resize);
|
||||
resize();
|
||||
|
||||
// Reaction-diffusion params
|
||||
const params = {
|
||||
feed: 0.055,
|
||||
kill: 0.062,
|
||||
dt: 1.0,
|
||||
scale: 40,
|
||||
diffuseA: 1.0,
|
||||
diffuseB: 0.5,
|
||||
// Energy/pulse mapping
|
||||
pulse: (Math.sin(Date.now() * 0.001) * 0.7 + 1.2) * 0.005
|
||||
};
|
||||
|
||||
let grid = [];
|
||||
let next = [];
|
||||
|
||||
function init() {
|
||||
const w = Math.floor(canvas.width / params.scale) + 2;
|
||||
const h = Math.floor(canvas.height / params.scale) + 2;
|
||||
|
||||
grid = Array(h).fill().map(() => Array(w).fill(0));
|
||||
next = Array(h).fill().map(() => Array(w).fill(0));
|
||||
|
||||
// Initial seeds (higher complexity = more scattered seeds)
|
||||
for (let i = 0; i < 120 * (0.5 + params.pulse * 2); i++) {
|
||||
const x = Math.floor(Math.random() * w);
|
||||
const y = Math.floor(Math.random() * h);
|
||||
grid[y][x] = 1 + Math.random() * 0.1;
|
||||
}
|
||||
}
|
||||
init();
|
||||
|
||||
function update() {
|
||||
const w = grid[0].length;
|
||||
const h = grid.length;
|
||||
|
||||
// Reaction and diffusion
|
||||
for (let y = 1; y < h - 1; y++) {
|
||||
for (let x = 1; x < w - 1; x++) {
|
||||
const a = grid[y][x];
|
||||
const b = next[y][x];
|
||||
|
||||
// Gray-Scott reaction
|
||||
const reaction = a * b * b;
|
||||
const newA = a + params.dt * (params.diffuseA * (grid[y-1][x] + grid[y+1][x] + grid[y][x-1] + grid[y][x+1] - 4*a) - reaction + params.feed * (1 - a));
|
||||
const newB = b + params.dt * (params.diffuseB * (next[y-1][x] + next[y+1][x] + next[y][x-1] + next[y][x+1] - 4*b) + reaction - (params.kill + params.feed) * b);
|
||||
|
||||
next[y][x] = newA;
|
||||
// B channel not stored (we use A for color)
|
||||
}
|
||||
}
|
||||
|
||||
// Swap buffers
|
||||
[grid, next] = [next, grid];
|
||||
|
||||
// Add pulse influence
|
||||
const px = Math.floor(canvas.width / (2 * params.scale));
|
||||
const py = Math.floor(canvas.height / (2 * params.scale));
|
||||
grid[py][px] = Math.min(1, grid[py][px] + params.pulse * 0.05);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
const w = grid[0].length;
|
||||
const h = grid.length;
|
||||
const imgData = ctx.createImageData(canvas.width, canvas.height);
|
||||
const data = imgData.data;
|
||||
|
||||
// Tone mapping (dryness=monochrome, curiosity=teal)
|
||||
const color = {
|
||||
r: 100 + Math.sin(Date.now() * 0.0005) * 30,
|
||||
g: 180 + Math.sin(Date.now() * 0.0003) * 20,
|
||||
b: 200 + Math.sin(Date.now() * 0.0007) * 25
|
||||
};
|
||||
|
||||
for (let y = 0; y < h - 2; y++) {
|
||||
for (let x = 0; x < w - 2; x++) {
|
||||
const val = grid[y+1][x+1];
|
||||
const intensity = Math.min(1, val) * (0.5 + params.pulse * 0.1);
|
||||
|
||||
const idx = (y * params.scale * canvas.width + x * params.scale) * 4;
|
||||
for (let dy = 0; dy < params.scale; dy++) {
|
||||
for (let dx = 0; dx < params.scale; dx++) {
|
||||
const pixelIdx = idx + (dy * canvas.width + dx) * 4;
|
||||
if (pixelIdx + 3 < data.length) {
|
||||
data[pixelIdx] = color.r * intensity;
|
||||
data[pixelIdx + 1] = color.g * intensity;
|
||||
data[pixelIdx + 2] = color.b * intensity;
|
||||
data[pixelIdx + 3] = 255 * intensity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
}
|
||||
|
||||
function animate() {
|
||||
update();
|
||||
draw();
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
animate();
|
||||
|
||||
// Interactive resonance
|
||||
addEventListener('mousemove', e => {
|
||||
const x = e.clientX / canvas.width;
|
||||
const y = e.clientY / canvas.height;
|
||||
const px = Math.floor(x * (canvas.width / params.scale));
|
||||
const py = Math.floor(y * (canvas.height / params.scale));
|
||||
if (px >= 0 && px < grid[0].length && py >= 1 && py < grid.length - 1) {
|
||||
grid[py][px] = Math.min(1, grid[py][px] + 0.3);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue