A lattice Boltzmann wind tunnel: draw any shape and watch it shed vortices.
The air is a D2Q9 lattice Boltzmann fluid: each cell holds nine particle populations that stream to their neighbours and relax toward equilibrium, which reproduces the Navier-Stokes equations. Obstacles use bounce-back walls, a Smagorinsky eddy viscosity keeps high Reynolds numbers stable, and a sponge layer lets sound waves leave the tunnel. Smoke streaklines released from a rake roll up into a von Karman vortex street behind the cylinder. The force on the obstacle comes from momentum exchange at the walls, giving live drag and lift coefficients, the Strouhal number of the shedding, and for the NACA 2412 airfoil a lift curve that builds up as the angle of attack rises.
Try it. Pick a cylinder, airfoil or plate, or drag anywhere to paint your own obstacle (right-click or Shift-drag erases, Draw starts from an empty tunnel). Slide the Reynolds number and the airfoil's angle of attack, and switch the view between smoke, vorticity, speed and pressure. Keys: 1 to 4 pick a shape, arrows change Re and the angle, V cycles views, R restarts the flow.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a 2D wind tunnel with the lattice Boltzmann method, in JavaScript and the HTML canvas element. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Use a grid of about 200 x 80 cells. Each cell stores nine numbers f0..f8, one per D2Q9 lattice velocity (rest, four axis directions, four diagonals), in Float32Arrays.
- Every step, do two things. Collide: compute the density (sum of f) and velocity (momentum over density), build the equilibrium distribution, and relax each f toward it with f += (feq - f) / tau. Stream: move each f one cell in its own direction.
- Viscosity is (tau - 0.5) / 3, so tau sets the Reynolds number. Start with an inflow speed of 0.1 and tau around 0.53.
- Hold the left column at the equilibrium for a steady wind blowing right, copy the second to last column into the last one as an outlet, and treat the top and bottom rows as free stream.
- Put a solid circle a quarter of the way in. Any population that would stream into a solid cell bounces straight back the way it came.
- Run 10 steps per animation frame and draw the vorticity (the curl of the velocity) with a blue to black to red color map, into a small ImageData scaled up with drawImage.
Once vortices start peeling off the cylinder, make it beautiful:
- Add smoke: release a point from each of 20 nozzles on the left every frame, move points with the interpolated velocity, and connect each nozzle's points into a line. Draw them glowing white over a dark background.
- Let the mouse paint and erase solid cells so I can test my own shapes.
- Compute the drag and lift on the obstacle by summing the momentum of every bounced population, and plot the lift over time.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as an airfoil with an angle of attack slider, a Smagorinsky turbulence model for higher Reynolds numbers, or a pressure view.