Quantised Fluid Sim
by soulwire
HTML
<canvas id="canvas"></canvas>
CSS
body {
margin: 0;
background: black;
overflow: hidden;
}
canvas {
display: block;
image-rendering: pixelated;
}
JavaScript
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let width = window.innerWidth;
let height = window.innerHeight;
canvas.width = width;
canvas.height = height;
const cellSize = 16;
const cols = Math.floor(width / cellSize);
const rows = Math.floor(height / cellSize);
let fluid = [];
let velocity = [];
for (let y = 0; y < rows; y++) {
fluid[y] = [];
velocity[y] = [];
for (let x = 0; x < cols; x++) {
fluid[y][x] = 0;
velocity[y][x] = 0;
}
}
let mouse = { x: 0, y: 0, down: false };
canvas.addEventListener('mousemove', (e) => {
mouse.x = Math.floor(e.clientX / cellSize);
mouse.y = Math.floor(e.clientY / cellSize);
});
canvas.addEventListener('mousedown', () => mouse.down = true);
canvas.addEventListener('mouseup', () => mouse.down = false);
function updateFluid() {
// Simple diffusion + damping
const diffusion = 0.2;
const damping = 0.98;
for (let y = 1; y < rows - 1; y++) {
for (let x = 1; x < cols - 1; x++) {
let avg = (
fluid[y][x] +
fluid[y - 1][x] +
fluid[y + 1][x] +
fluid[y][x - 1] +
fluid[y][x + 1]
) / 5;
velocity[y][x] += (avg - fluid[y][x]) * diffusion;
velocity[y][x] *= damping;
}
}
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
fluid[y][x] += velocity[y][x];
fluid[y][x] *= 0.99; // fade out
}
}
if (mouse.down) {
for (let dy = -1; dy <= 1; dy++) {
for (let dx = -1; dx <= 1; dx++) {
const x = mouse.x + dx;
const y = mouse.y + dy;
if (x >= 0 && x < cols && y >= 0 && y < rows) {
fluid[y][x] = 1;
}
}
}
}
}
function densityToSymbol(v) {
if (v < 0.05) return ' ';
if (v < 0.15) return '.';
if (v < 0.3) return '/';
if (v < 0.45) return '\\';
if (v < 0.6) return '+';
if (v < 0.8) return 'x';
return '-';
}
function...