createCanvas(nx * view_scale, ny * view_scale);
for (var i=0; i<nx*ny; ++i) {
vel[i] = {"x": 0, "y": 0};
seed_particles(particles, num_particles);
function seed_particles(parts, num) {
var radius = min(nx / 2, ny / 2);
for (var p=0; p<num; ++p) {
var rangle = random() * TWO_PI;
var rdist = random() * radius;
parts[p] = {"x": center_x + cos(rangle) * rdist, "y": center_y + sin(rangle) * rdist, "len": 0};
parts[p].px = parts[p].x;
parts[p].py = parts[p].y;
function get_potential(x, y, res_x, res_y, time) {
var distmult = pow(1 / (min(res_x, res_y)/2), 2);
var dist_center = max(1 - (pow(x - res_x/2, 2) + pow(y - res_y/2, 2)) * distmult, 0);
return (noise(x*detail, y*detail, time) * 2 - 1) * pot_scale * dist_center;
function vel_from_pot(vel_arr, res_x, res_y) {
var time = frameCount * 0.005;
for (var y=1; y<res_y-1; ++y) {
for (var x=1; x<res_x-1; ++x) {
vel_arr[IX(x,y)] = {"x": -(get_potential(x,y+dx, res_x, res_y, time) - get_potential(x,y-dx, res_x, res_y, time)) / (2*dx),
"y": (get_potential(x+dx,y, res_x, res_y, time) - get_potential(x-dx,y, res_x, res_y, time)) / (2*dx)};
vel_from_pot(vel, nx, ny);
for (var p=0; p<num_particles; ++p) {
advect_particle(particles[p], vel, nx, ny);
stroke(255 - min(int(abs(particles[p].x-particles[p].px) * 100), 255), 255 - min(int(abs(particles[p].y-particles[p].py) * 100), 255), min(int(particles[p].len * 500), 255));
strokeWeight(particles[p].len * 3);
line(particles[p].px * view_scale, particles[p].py * view_scale, particles[p].x * view_scale, particles[p].y * view_scale);
particles[p].px = particles[p].x;
particles[p].py = particles[p].y;