This notebook reworks my Periodic Planar Three-Body Orbits notebook with a bit of an odd goal: to animate periodic planar three-body orbits using pure HTML and CSS, without any JavaScript, and without fully enumerating every point along the paths.
The method is straightforward though a bit tedious. We integrate an orbit with fixed temporal spacing, assign the x and y components of each point along the trajectory to real and imaginary components in the complex plane, and compute the Discrete Fourier Transform (DFT). Then we threshold the frequency components, represent each frequency component as a rotating complex phasor, and convert to CSS transforms!
For a delightful illustration of the method, see Mike Bostock’s Fourier Series - Zoom notebook in which he illustrates drawing a portrait using the sum of complex phasors.
The most challenging aspect was converting the phasors to CSS, but in the end I was able to represent them as a chain of transforms in the style transform(\${re}px, \${im}px) rotate(\${f}deg) where re and im are precisely the DFT components, and the frequency f is the component’s frequency relative to the sum total of all parent rotations, so that the rotational speed of the component is correct. (Thanks, Fabian Iwand for digging up the CSS transform interpolation specification and confirming that parallel lists of transforms are matched up and interpolated one transform at a time!)
Realistically, complex orbits require quite a few frequency components and actually end up quite large, but you can get a lovely figure-eight in just a little over two kilobytes. The rest of this notebook walks through the computation step by step.
We start by selecting initial conditions and integrating the trajectory. The integrator uses an adaptive Runge-Kutta scheme (Cash-Karp) which adjusts the time step to maintain accuracy, saving the output at fixed temporal spacing. This is important because the bodies move slowly when far apart but very quickly during close encounters, so adaptive integration is dramatically more efficient than fixed step methods. The Broucke orbits and the Figure-Eight orbits compress particularly well.
With the trajectory computed, we take the DFT of each body’s path, treating x and y as the real and imaginary parts of a complex signal. We then threshold the frequency components to keep only the significant ones. The plot below shows the filtered orbit overlaid on the original integrated trajectory in gray. Adjust the threshold to control how many frequency components are retained and observe the tradeoff between fidelity and the number of CSS transforms required.
Convert to CSS
Finally, we convert the filtered frequency components into CSS keyframe animations. Each retained component becomes a nested rotate and translate transform. The from state starts with zero rotation and the to state applies the component’s frequency as a full rotation, so that the browser interpolates the rotation smoothly over the animation’s duration. The result is a pure HTML+CSS animation with no JavaScript at runtime.