The physics of a flock without feathers

Reviewing the bird-physics literature and building a tunable simulation of the collective motion of a flock

Preparing the flock…
Change the bird equation
Ai=wiJ(vNivi)alignment+\displaystyle \mathbf A_i=\underbrace{w_iJ(\overline{\mathbf v}_{\mathcal N_i}-\mathbf v_i)}_{\text{alignment}}\,+wiC(xNixi)cohesion+\displaystyle \underbrace{w_iC(\overline{\mathbf x}_{\mathcal N_i}-\mathbf x_i)}_{\text{cohesion}}\,+SjRi(1rij/r0)xixjrijseparation+\displaystyle \underbrace{S\sum_{j\in\mathcal R_i}(1-r_{ij}/r_0)\frac{\mathbf x_i-\mathbf x_j}{r_{ij}}}_{\text{separation}}\,+Eidisturbance+\displaystyle \underbrace{\mathbf E_i}_{\text{disturbance}}\,+Riroost+\displaystyle \underbrace{\mathbf R_i}_{\text{roost}}\,+Bialtitude+\displaystyle \underbrace{\mathbf B_i}_{\text{altitude}}\,+ηivariation\displaystyle \underbrace{\boldsymbol\eta_i}_{\text{variation}}
Target acceleration · terms and update rule ↓
Alignment of the flock 0.00Mean speed 0.0 m/sWhat do these controls mean? ↓

A few thousand birds can turn together, stretch into a ribbon, or divide around an obstacle without anyone appearing to direct traffic.

One way to animate a flock is to decide where every bird should go and draw the paths. Craig Reynolds took a different approach in his 1987 paper on boids. He gave simulated individuals local behaviors: avoid crowding, align with nearby individuals, and stay near the group. The flock’s motion followed from repeatedly applying those rules. As his abstract puts it, the birds (or equivalently boids for New Yorkers) “choose their own course” (Reynolds, 1987).

That is a useful start, but it leaves a lot unspecified. What counts as nearby? Do birds align their directions or their full velocities? How quickly can they turn? What happens when avoiding a collision conflicts with keeping up?

Birds are not a gas at equilibrium (and flocks cannot be approximated as a sphere for that matter)

The connection to statistical physics is fairly direct. We have many interacting degrees of freedom, local fluctuations, and a collective state. But birds continually consume energy to move. Their speed does not simply decay by drag until everything comes to rest. They are examples of active matter: the constituents take in energy and convert it into motion or mechanical work (Ramaswamy, 2010).

These systems, as you can imagine, don't gradually settle to equilibrium. For birds, dissipation includes energy transferred to the air and heat. Flocks of birds form these familiar collective swarms. Walk under a flock and you may find out what else they dissipate on your freshly washed clothes.

In the model introduced by Vicsek and collaborators in 1995, particles move at a fixed speed and update their headings toward the local average, with added directional noise. There is no leader supplying the direction of travel. Nevertheless, coordinated motion can emerge (Vicsek et al., 1995). This simplified mechanic lets us ask about ordering without first determining the biomechanics of a wing, much as we can predict the orbit of a planet without worrying so much about how matter is distributed within it.

A convenient measure of directional order is the polarization,

P=1Ni=1Nu^i,P=\left|\frac{1}{N}\sum_{i=1}^{N}\hat{\mathbf u}_i\right|,

where u^i\hat{\mathbf u}_i is the unit vector along bird ii’s velocity and NN is the number of birds. If all headings agree, P=1P=1. If headings largely cancel, PP is small. However, this does not tell us everything. An organized flock moving around a circle can have a small total polarization.

Toner and Tu instead described slowly varying density and velocity fields. Their 1995 continuum equations are

tv+(v)v=αvβv2vp+DL(v)+D12v+D2(v)2v+f,tρ+(ρv)=0.\begin{aligned} \partial_t\mathbf v+(\mathbf v\cdot\nabla)\mathbf v &=\alpha\mathbf v-\beta|\mathbf v|^2\mathbf v-\nabla p +D_L\nabla(\nabla\cdot\mathbf v)\\ &\quad+D_1\nabla^2\mathbf v+D_2(\mathbf v\cdot\nabla)^2\mathbf v+\mathbf f,\\ \partial_t\rho+\nabla\cdot(\rho\mathbf v)&=0. \end{aligned}

Here ρ\rho is number density, v\mathbf v is the coarse-grained velocity, and f\mathbf f is random forcing. The density-dependent pressure is written pp here to distinguish it from polarization. The α,β\alpha,\beta terms select a nonzero speed when α>0\alpha>0, the DD terms smooth spatial variations, and the second equation conserves bird number (Toner and Tu, 1995).

The convective term (v)v(\mathbf v\cdot\nabla)\mathbf v carries orientation as the individuals move and exchange neighbors. Their analysis finds stable orientational order even in two dimensions. A moving state selects a direction although the equations select none: spontaneous symmetry breaking away from equilibrium. The equilibrium Mermin–Wagner restriction therefore does not decide this problem. The conclusion depends on the nonlinear dynamics, not just the uniform solution v=α/β|\mathbf v|=\sqrt{\alpha/\beta} (Toner and Tu, 1995).

Seven neighbors \neq seven meters

Suppose every bird responds to all other birds within a fixed radius. Compress the flock and the number of interaction partners increases. Let it spread out and that number decreases; eventually some birds lose contact altogether. This is a metric neighborhood,

Nimetric={ji:xjxi<r}.\mathcal N_i^{\rm metric}=\{j\ne i:|\mathbf x_j-\mathbf x_i|<r\}.

It selects the other birds whose positions lie inside an open ball in the language of metric spaces. In flocking, a topological neighborhood usually means a fixed number of nearest individuals. Their distances change as the flock expands, but their number does not. This specialized usage is about neighbor rank. “The seventh closest bird” is a different instruction from “every bird within seven meters.”

Ballerini and company used three-dimensional reconstructions of starling flocks to investigate this distinction. They inferred an interaction range from the anisotropy of neighbor positions: nearby birds were not distributed uniformly around a reference bird, and that directional structure weakened with increasing neighbor rank. Across flocks with different densities, their results supported roughly six or seven* neighbors rather than a constant distance (Ballerini et al., 2008).

* A notable pair of numbers in these modern times

Neighbor-position anisotropy approaches its isotropic value of one third near the sixth or seventh neighbor in two measured flocks.
Figure 1. “For both flocks, the structure becomes approximately isotropic between the sixth and the seventh nearest neighbor.” The labels 32-06 and 25-11 identify two reconstructed flock events, containing 781 and 1,168 birds, respectively. The horizontal line marks the isotropic value γ=1/3\gamma=1/3. Panel reproduced from Ballerini et al. (2008), supplied as a crop.

The inference of seven comes from spatial structure and is experimentally motivated as a starting point; it does not directly record which birds each individual was watching. Let's bring that into our working model.

There is also no reason to make every interaction topological. Two bodies can collide whether they are each other’s first or twentieth neighbor. The model for this article uses nearest-neighbor selection for social coordination and a separate distance-dependent rule for close encounters.

Try changing the neighbor count while leaving the other settings alone. Increasing it changes which information each bird averages. That doesn't guarantee a more responsive flock, as averaging over more individuals may also dilute a local changes.

What starts a turnaround?

The original version of this animation had a straightforward problem: strong alignment, weak individual fluctuations, and no horizontal environmental preference. Adding a bird leading the pack on a prescribed route would create turns, but would also supply much of the answer in advance.

In a study of spontaneous turns, Attanasi and collaborators found initiators near the flock’s outer tips (Attanasi et al., 2015).

For the scene here, I have added a preference to remain near a roost. Hildenbrandt, Carere, and Hemelrijk’s StarDisplay combines local coordination with simplified flight mechanics and attraction toward a roosting region. Its horizontal return response depends on the bird’s heading: stronger when flying outward, weaker when already returning (Hildenbrandt et al., 2010).

Our birds similarly turn back after leaving a region, then continue inward before releasing that preference. They respond individually and influence their neighbors through the social terms discussed in What the simulation does.

How far does a turn travel?

A flock can have high polarization and still respond badly when something happens. Everyone might be traveling in the same direction, yet a turn by a few individuals could be lost before it reaches the rest. Photos of starling flocks alone don't settle this question.

In 2010, Cavagna and collaborators measured correlations between velocity fluctuations in starling flocks. The range of those correlations grew with the flock’s linear size. This is the sense in which the correlations were called scale free, meaning they did not reveal a fixed correlation length independent of the size of the group (Cavagna et al., 2010).

Speed correlation length rises approximately linearly with the measured flock's linear size.
Figure 2. The speed fluctuations correlation length ξsp\xi_{\rm sp} grows approximately as ξsp=aL\xi_{\rm sp}=aL, where LL is the flock’s linear size and aa is the fitted slope. Reproduced from Cavagna et al. (2010), speed-correlation panel; supplied crop.

A bird can interact directly with a few neighbors while sharing correlated fluctuations with birds much farther away. You might interact regularly with a small group of friends and share tastes with a much wider circle. But by the time you get to Kevin Bacon (see Six Degrees of Kevin Bacon), there likely isn't much in common. Interaction range \neq correlation length.

The distinction is made clear during a turn. Attanasi and collaborators reconstructed turning starling flocks and found directional information propagating with a “linear dispersion law and negligible attenuation.” Their theory introduced behavioral inertia: resistance to changing the curvature of a flight path. In the nearly planar, ordered limit, their equations (6) and (8) read (Attanasi et al., 2014)

tφ=szχ,tsz=a2J2φt2φ=cs22φ,cs2=a2Jχ.\partial_t\varphi=\frac{s_z}{\chi},\qquad \partial_t s_z=a^2J\nabla^2\varphi \quad\Longrightarrow\quad \partial_t^2\varphi=c_s^2\nabla^2\varphi,\qquad c_s^2=\frac{a^2J}{\chi}.

Here φ\varphi is the heading angle, szs_z is its conjugate spin variable, χ\chi is behavioral inertia, aa is the average nearest-neighbor spacing, and JJ is the theory’s alignment stiffness. These are the paper’s variables, not numerical values taken from our sliders. The resulting wave equation carries a turn with speed csc_s.

The same paper explains why paths can cross during an equal-radius turn. Birds on opposite sides follow similar curved paths at similar speeds, changing their positions relative to the travel direction. Crossing trajectories do not imply a collision since their crossing points can be reached at different times, and projected paths can overlap at different heights.

Why a flock darkens and divides

A bird presents a different silhouette when it banks. If nearby birds copy that maneuver, a dark band can travel through the flock without an equally large change in density. Hemelrijk and collaborators reproduced this effect with rolling maneuvers in a model of agitation waves (Hemelrijk et al., 2015). A two-dimensional view can also make birds at different heights appear to pass through one another.

Banking changes more than the view. Tilting the lift force makes some of it available for turning and leaves less to oppose gravity. Unless the bird increases lift, it loses height. In StarDisplay, coupling turns to flight mechanics helped produce changing flock shapes (Hemelrijk and Hildenbrandt, 2011). Our birds now have a bank angle and a lift response that affect their trajectories, rather than only tilting a mesh after the turn has happened.

A split doesn't have to divide the flock in half. Papadopoulou and collaborators studied flocks pursued by a robotic falcon: different birds turned or dived at different times, and some groups separated while others remained connected (Papadopoulou et al., 2026). Those observations concern escape behavior. They do not establish that every changing flock shape requires a predator.

Occasional disturbances arise near the flock’s edge. Affected birds briefly prioritize a turn or dive, and neighbors can copy it after a delay. The response weakens as it spreads. Neither the number of resulting groups nor their sizes is specified. Once the maneuver ends, normal coordination returns; groups can join again when their paths bring them close. The disturbance’s cause is not simulated, and its timing and strength are chosen for this demonstration.

What the simulation does

The equations below specify an effective steering model. Their parameters have not been fitted to bird trajectories. In particular, the steering response time is not a measurement of behavioral inertia.

Bird ii has position xi\mathbf x_i, velocity vi\mathbf v_i, and heading u^i=vi/vi\hat{\mathbf u}_i=\mathbf v_i/|\mathbf v_i|. Its target acceleration, Ai\mathbf A_i, is the sum of the responses below. Distances are in meters and time is in seconds.

1. Choose the neighbors

Ni\mathcal N_i is the set of the nearest kk birds. A bar is their average: for example, vNi=k1jNivj\overline{\mathbf v}_{\mathcal N_i}=k^{-1}\sum_{j\in\mathcal N_i}\mathbf v_j. If fewer than kk candidates are available, the average uses that smaller number. An empty set contributes no social attraction or alignment.

Below 20,000 birds, a spatial tree repeatedly partitions the positions into smaller regions. Its distance bounds let the search skip regions that cannot contain a closer bird. It finds the nearest 24 birds without comparing every possible pair; the first kk contribute to the social coordination term.

2. Match velocity and stay together

Aialign=J(vNivi),Aicohere=C(xNixi).\mathbf A_i^{\rm align}=J(\overline{\mathbf v}_{\mathcal N_i}-\mathbf v_i),\qquad \mathbf A_i^{\rm cohere}=C(\overline{\mathbf x}_{\mathcal N_i}-\mathbf x_i).

The first term reduces differences in speed and direction. Its strength JJ has units s1\mathrm{s^{-1}}. The second pulls toward the neighbors’ average position, with CC in s2\mathrm{s^{-2}}. Increasing the neighbor count changes the information available to the bird. Increasing these strengths makes it respond more strongly to that information.

3. Leave room for wings

Aiseparate=SjRi(1rijr0)xixjrij,rij=xixj.\mathbf A_i^{\rm separate}=S\sum_{j\in\mathcal R_i}\left(1-\frac{r_{ij}}{r_0}\right)\frac{\mathbf x_i-\mathbf x_j}{r_{ij}}, \qquad r_{ij}=|\mathbf x_i-\mathbf x_j|.

Ri\mathcal R_i contains nearby candidates within the personal-space radius r0r_0. Repulsion acts along the line between the two birds and decreases linearly to zero at r0r_0. Here S=10ms2S=10\,\mathrm{m\,s^{-2}}. Repulsion is evaluated for up to 24 candidates. Birds at the same position are assigned opposite directions using a reproducible seeded choice.

4. Return toward the roost

Local cohesion keeps neighbors together, but supplies no reason to revisit a particular place. The roost response Ri\mathbf R_i adds that environmental preference. A bird starts returning after leaving the roost radius RR and continues until it reaches 0.45R0.45R.

Ri=qiKR1+h^in^i2tanh ⁣[8(n^i)l^i]l^i.\mathbf R_i=q_iK_R\frac{1+\hat{\mathbf h}_i\cdot\hat{\mathbf n}_i}{2} \tanh\!\left[8(-\hat{\mathbf n}_i)\cdot\hat{\mathbf l}_i\right]\hat{\mathbf l}_i.

qiq_i is 1 during a return and 0 otherwise. h^i\hat{\mathbf h}_i is the horizontal heading, n^i\hat{\mathbf n}_i points horizontally from the roost to the bird, and l^i=(hiz,0,hix)\hat{\mathbf l}_i=(h_{iz},0,-h_{ix}) points sideways. The dot products determine how far the bird points outward and which way to turn inward. The hyperbolic tangent smoothly limits the signed turn command. An exactly radial heading uses a small seeded left-or-right choice to break the tie.

The roost slider sets KRK_R in acceleration units. At zero, horizontal flight is unrestricted. The default radius is

R=45m+1.5E,E=10m[max(N,80)/3000]1/3R=45\,\mathrm m+1.5E,\quad E=10\,\mathrm m\,[\max(N,80)/3000]^{1/3}

Here EE sets the initial cloud’s size. The fixed roost center is (25,0,30)m(-25,0,-30)\,\mathrm m and the cloud begins near (0,20,0)m(0,20,0)\,\mathrm m. This offset avoids an artificially symmetric launch directly away from the center. These are chosen scene conditions. The return memory and smooth turn command are my implementation choices, inspired by StarDisplay’s heading-dependent roost attraction.

5. Choose altitude and individual variation

Bi\mathbf B_i has only a vertical component. It strengthens when the predicted height two seconds ahead falls below 11 meters or above 34 meters, with a weaker preference for 20 meters. The remaining term, ηi\boldsymbol\eta_i, gives each bird a smoothly changing individual preference.

Altitude and noise equationsBiy=1.6s2max(11myi2sviy,0)1.2s2max(yi+2sviy34m,0)+0.015s2(20myi)0.025s1viy.B_{iy}=1.6\,\mathrm{s^{-2}}\max(11\,\mathrm m-y_i-2\,\mathrm s\,v_{iy},0) -1.2\,\mathrm{s^{-2}}\max(y_i+2\,\mathrm s\,v_{iy}-34\,\mathrm m,0) +0.015\,\mathrm{s^{-2}}(20\,\mathrm m-y_i)-0.025\,\mathrm{s^{-1}}v_{iy}.η=eh/tcη+σ1e2h/tcξ,tc=1.8s.\eta'=e^{-h/t_c}\eta+\sigma\sqrt{1-e^{-2h/t_c}}\,\xi,\qquad t_c=1.8\,\mathrm s.

Each component follows this noise update independently. hh is the elapsed time between perception updates, ξ\xi is a seeded standard normal sample, and σ\sigma sets the long-time standard deviation of each component. The exponential factor retains some of the preceding preference over correlation time tct_c.

6. Respond to a local disturbance

The disturbance response is a temporary preference of direction. At the first automatic event after five simulated seconds, and then at intervals chosen uniformly between 16 and 28 seconds, a randomly oriented edge of the flock receives a local disturbance. Its radius is max(2m,0.42E)\max(2\,\mathrm m,0.42E).

ei(t)={aisin[π(tti)/Ti],tit<ti+Ti,0,otherwise,wi=10.95ei.e_i(t)=\begin{cases}a_i\sin[\pi(t-t_i)/T_i],&t_i\le t<t_i+T_i,\\0,&\text{otherwise},\end{cases}\qquad w_i=1-0.95e_i.Ei=ei[(12ms2)sil^i(7ms2)diy^].\mathbf E_i=e_i\left[(12\,\mathrm{m\,s^{-2}})s_i\hat{\mathbf l}_i-(7\,\mathrm{m\,s^{-2}})d_i\hat{\mathbf y}\right].

Here si=±1s_i=\pm1 chooses the turn direction and did_i sets the downward component. The directly affected patch shares a turn direction. Some events include a dive whose strength varies with position within that patch. The pulse amplitude aia_i starts between 0.75 and 1; the duration TiT_i is chosen between 2.8 and 3.6 seconds. Alignment and cohesion are multiplied by wiw_i during the maneuver. Separation and environmental responses remain active.

An eligible bird copies the strongest active maneuver among its social neighbors after a delay chosen between 0.12 and 0.28 seconds. It retains 96% of the donor’s amplitude; copying stops below amplitude 0.25. A bird responds at most once to the same disturbance, then waits five seconds after its maneuver before responding to another. Pending responses cannot propagate until their start time, so updating birds in an array does not transmit a disturbance instantly. These timings, damping, and strengths are explicit modeling choices, not fitted measurements.

Putting those responses together gives the bird equation shown in the controls:

Ai=wiJ(vNivi)alignment+wiC(xNixi)cohesion+SjRi(1rij/r0)xixjrijseparation+Eidisturbance+Riroost+Bialtitude+ηivariation\mathbf A_i=\underbrace{w_iJ(\overline{\mathbf v}_{\mathcal N_i}-\mathbf v_i)}_{\text{alignment}}+\underbrace{w_iC(\overline{\mathbf x}_{\mathcal N_i}-\mathbf x_i)}_{\text{cohesion}}+\underbrace{S\sum_{j\in\mathcal R_i}(1-r_{ij}/r_0)\frac{\mathbf x_i-\mathbf x_j}{r_{ij}}}_{\text{separation}}+\underbrace{\mathbf E_i}_{\text{disturbance}}+\underbrace{\mathbf R_i}_{\text{roost}}+\underbrace{\mathbf B_i}_{\text{altitude}}+\underbrace{\boldsymbol\eta_i}_{\text{variation}}

From a target to motion

A bird cannot instantly adopt the entire requested acceleration. First separate the turning part from the part that changes speed. The matrix Pi=Iu^iu^iT\mathsf P_i=\mathsf I-\hat{\mathbf u}_i\hat{\mathbf u}_i^{\mathsf T} removes the component along the heading; I\mathsf I is the identity matrix. Define capa(w)=wmin(1,a/w)\operatorname{cap}_a(\mathbf w)=\mathbf w\min(1,a/|\mathbf w|) for a nonzero vector, and zero for a zero vector. This limits its length without changing its direction.

Ti=capamax(PiAi),bin+1=bin+(1eΔt/τ)(Tibin).\mathbf T_i=\operatorname{cap}_{a_{\max}}(\mathsf P_i\mathbf A_i),\qquad \mathbf b_i^{n+1}=\mathbf b_i^n+(1-e^{-\Delta t/\tau})(\mathbf T_i-\mathbf b_i^n).

Ti\mathbf T_i is the limited turning target, bi\mathbf b_i is the stored steering acceleration, and superscript nn labels the current step. Over one step Δt=1/30s\Delta t=1/30\,\mathrm s, steering moves partway toward the target. The slider τ\tau controls how gradually it responds.

Banking changes the flight path

Let l^i\hat{\mathbf l}_i point sideways and e^u,i=u^i×l^i\hat{\mathbf e}_{u,i}=\hat{\mathbf u}_i\times\hat{\mathbf l}_i point upward perpendicular to the heading. The stored steering projected onto these directions gives requests blb_l and bub_u. A reduced pitch controller limits the upward request to keep ordinary flight away from vertical aerobatics:

θi=arcsin(uiy),bu=clip[κ(θ0θi),κ(θ0θi)](bu),θ0=0.55,κ=20ms2.\theta_i=\arcsin(u_{iy}),\qquad b_u'=\operatorname{clip}_{[\kappa(-\theta_0-\theta_i),\,\kappa(\theta_0-\theta_i)]}(b_u),\quad \theta_0=0.55,\quad \kappa=20\,\mathrm{m\,s^{-2}}.

Angles are in radians. With g=9.81ms2g=9.81\,\mathrm{m\,s^{-2}} and Vi=bu+geu,iyV_i=b_u'+g e_{u,iy}, the requested bank and lift per unit mass are

ϕi=clip[1.03,1.03]atan2[bl,max(0.1g,Vi)],i=clip[0,2.2g](Vicosϕi).\phi_i^*=\operatorname{clip}_{[-1.03,1.03]}\operatorname{atan2}[b_l,\max(0.1g,V_i)],\qquad \ell_i^*=\operatorname{clip}_{[0,2.2g]}\left(\frac{V_i}{\cos\phi_i^*}\right).

The actual bank ϕi\phi_i and specific lift i\ell_i relax toward these requests by the same exponential update used above. The response time is 0.22 seconds when rolling farther into a bank, 0.44 seconds when rolling out, and 0.65 seconds for lift. Because lift lags behind banking, a turn can initially lose height. The resulting turning acceleration is

f,i=isinϕil^i+(icosϕigeu,iy)e^u,i.\mathbf f_{\perp,i}=\ell_i\sin\phi_i\,\hat{\mathbf l}_i+ (\ell_i\cos\phi_i-g e_{u,iy})\hat{\mathbf e}_{u,i}.

This resolves lift and the perpendicular component of gravity. The speed controller below stands in for propulsion and drag, including compensation for gravity along the heading. Bank angle now enters the acceleration itself. The response times, pitch envelope, and lift limit are chosen simplifications; this is not a complete aerodynamic model.

a,i=clip[as,as][v0viτv+u^iAi],τv=1.25s,as=2.5ms2.a_{\parallel,i}=\operatorname{clip}_{[-a_s,a_s]}\left[\frac{v_0-|\mathbf v_i|}{\tau_v}+\hat{\mathbf u}_i\cdot\mathbf A_i\right], \qquad \tau_v=1.25\,\mathrm s,\quad a_s=2.5\,\mathrm{m\,s^{-2}}.

a,ia_{\parallel,i} changes speed along the heading. The first contribution relaxes speed toward the preferred value v0v_0; the second preserves the forward social response, so a bird can slow behind another or catch up. The clip operation limits this acceleration to the interval shown.

vi=vin+Δt[f,in+1+a,iu^i],xin+1=xin+Δtvin+1.\mathbf v_i^*=\mathbf v_i^n+\Delta t[\mathbf f_{\perp,i}^{n+1}+a_{\parallel,i}\hat{\mathbf u}_i], \qquad \mathbf x_i^{n+1}=\mathbf x_i^n+\Delta t\,\mathbf v_i^{n+1}.

Before advancing position, the candidate velocity vi\mathbf v_i^* is rescaled to the intended speed clip[0.64v0,1.36v0](vin+Δta,i)\operatorname{clip}_{[0.64v_0,1.36v_0]}(|\mathbf v_i^n|+\Delta t\,a_{\parallel,i}). Its total change from the preceding velocity is then limited to amaxΔta_{\max}\Delta t, with amax=12ms2a_{\max}=12\,\mathrm{m\,s^{-2}}. That final limit also applies after a slider change. This discrete rule defines the browser model.

The shortcut for large flocks

At 20,000, 50,000, and 100,000 individuals, three-meter grid cells replace the tree. The search examines at most 64 candidates from 27 adjacent cells, with at most 12 from any one cell. The nearest 24 of those candidates supply the same force terms. They don't need to be the globally nearest birds. This is my spherical cow for your computer’s sake.

Perception updates every two physics steps below 10,000 birds, every four at 10,000 and 20,000, and every ten at 50,000 and 100,000. From 10,000 birds upward, this work is staggered across birds, while all positions and velocities advance at 30 Hz in simulation time. Noise uses the corresponding elapsed perception time. Because the search, sampling interval, and roost size vary, these modes are not all-else-controlled-for finite-size comparisons.

Playback runs at 1.5× speed: one second on screen advances the model by 1.5 seconds. The fixed timestep and all physical parameters stay the same; the worker performs more steps per second of wall-clock time.

From the equation to the update loop

Every target uses the same old positions and velocities; a disturbance copied in this pass starts in the future. Otherwise, birds later in the loop would effectively see into the future.

every 1/30 second of simulation time (1.5x playback):
    update local disturbance pulses and any new disturbance
    on a perception step:
        organize current positions for the neighbor search
        for each bird due to update its perception:
            find up to 24 nearby candidates
            average the nearest k positions and velocities
            schedule delayed copying of a nearby maneuver, if eligible
            reduce social response during escape; add its turn/dive command
            add repulsion from candidates within personal space
            update its return-to-roost state
            add roost turning, altitude response, and correlated noise
            store the target acceleration

    for each bird, using the same previous state:
        separate target acceleration into sideways and forward parts
        limit the sideways target and gradually adjust stored steering
        update bank angle and lift toward the steering request
        resolve lift and gravity to obtain turning acceleration
        combine the forward target with preferred-speed regulation
        update velocity, limiting speed and total velocity change

    for each bird:
        advance position with its new velocity
    send a snapshot to the display

while the panel is visible and playing, up to 120 frames per second:
    interpolate between completed simulation states on the GPU
    follow the flock with the camera
    draw shared bird meshes, or small points for 50,000 and above

Read the movement rules · Read the timing loop

Making motion look like a flock

The displayed orientation uses the bank angle from the flight controller above. The changing wing silhouette can therefore change the flock’s apparent darkness. The 50,000- and 100,000-point modes retain the movement rules but cannot display that wing-area effect. Wingbeats are just an animation and do not contribute in any aerodynamic way.

The camera follows the flock and adjusts its distance gently. Ground and horizon are optional scenery. Both the drawing and physics pause while the simulation is offscreen, so reading about birds gives the computer a rest.

And, because there are technically no feathers on our bird…

Behold! Plato’s Man!

This here sparrow has a 24-centimeter wingspan is made of 882 triangles. It was made with OpenAI’s GPT-6 Astra using the Computer Use tool in Blender, before I learned of the obsession the bird-watching physicists have with the starling.

Preparing the sparrow…
House sparrow · 24 cm wingspan

As you can see by starting its wingbeat, this poor featherless bird's skull deforms with every never-ending flap of its wings. And with a few thousand more, we have our flock.

References & further reading