Exact flow past a wing, made by conformally mapping flow around a circle.
Potential flow around a spinning cylinder has an exact formula. The Joukowski map z = zeta + 1/zeta bends a circle through zeta = 1 into a wing with a sharp trailing edge, and because the map is conformal it carries the whole flow along with it. The circulation is set by the Kutta condition, which puts the rear stagnation point (yellow) on the trailing edge, and the Kutta-Joukowski theorem turns that circulation into lift. Streamlines are contours of the stream function on a log-polar grid around the circle, mapped to the wing; the background is the pressure coefficient with alternate stream tubes tinted, and dye pulses integrated through the exact velocity show the air over the top reaching the trailing edge long before the air underneath.
Try it. Drag up or down to change the angle of attack. Drag the circle's centre in the inset to reshape the wing: up adds camber, left adds thickness. Turn off the Kutta condition to see the unphysical flow that whips around the trailing edge with no lift, morph back to the original circle, and switch the background between pressure, speed and plain ink. Keys: arrows for the angle, WASD for the centre, K, M and V.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build an interactive Joukowski airfoil: exact potential flow around a wing, drawn with 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:
- Write a few tiny complex number helpers (add, multiply, divide, square root) working on [re, im] pairs.
- In the "circle plane" zeta, take a circle with centre mu = (-0.1, 0.1) and radius R = |1 - mu|, so it passes through zeta = 1.
- The flow around it, with a free stream at angle alpha and circulation Gamma, has the complex potential w = (zeta - mu) e^(-i alpha) + R^2 e^(i alpha) / (zeta - mu) + (i Gamma / 2 pi) log(zeta - mu). Set Gamma = 4 pi R sin(alpha + beta), where beta = atan2(mu.im, 1 - mu.re). That is the Kutta condition.
- The Joukowski map z = zeta + 1/zeta turns the circle into a wing. Draw the wing by mapping 300 points of the circle.
- Draw streamlines: release 30 points on the left, and step each one along the velocity. To get the velocity at a point z, invert the map (zeta = (z + sqrt(z^2 - 4)) / 2, picking the root outside the circle), then velocity = conj(dw/dzeta / (1 - 1/zeta^2)).
Once the wing and its streamlines look right, make it beautiful:
- Color the background by the pressure coefficient Cp = 1 - |V|^2: blue where the air is fast and the pressure low, warm where it stagnates.
- Release vertical lines of dye every half second and advect them. Watch the upper part reach the trailing edge first.
- Let the mouse change the angle of attack and drag the circle centre to reshape the wing, and show the lift coefficient 2 Gamma / chord.
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 a button that turns the Kutta condition off, a surface pressure plot, or animating the map from circle to wing.