A spinning neutron star's beams become dispersed radio sweeps you de-disperse by hand.
A neutron star turns with its magnetic axis tilted, and the beam intensity toward Earth comes from the spherical cosine rule between the pole and our line of sight, which gives the pulse profile and, for near-orthogonal rotators, an interpulse. Every channel of a simulated 400 to 800 MHz receiver is generated with the true cold plasma delay of 4.149 ms times DM times the difference of inverse squared frequencies, plus radiometer noise, scintillation, f to the minus 4 scattering tails, pulse-to-pulse jitter and nulls, and radio interference. The waterfall shifts each channel back by the delay for your trial DM: wrong and the pulses are curved sweeps, right and they snap upright while the band sum spikes. A background search scores every trial DM on the same buffer with a median-based signal-to-noise, folding at the period builds the average profile, and the peak DM divided by the mean electron density gives a distance.
Try it. Drag the DM slider, or drag sideways across the waterfall, to de-disperse (the arrow keys nudge it). Drag the star to tilt its magnetic axis and turn the view, up and down arrows change the sight line, and N finds a new pulsar. Click for sound: a dispersed pulse is a falling whistle, a de-dispersed one a crisp tick. M mutes.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a pulsar de-dispersion toy 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:
- Make a canvas that fills the window, stays sharp on high-DPI screens (scale by devicePixelRatio), and resizes with the window. Use a near-black background.
- Simulate a radio receiver with 64 frequency channels from 400 to 800 MHz, sampled every 6 ms. Keep the last few seconds of samples per channel in a ring buffer.
- A pulsar with period 0.7 s emits a narrow Gaussian pulse once per turn. Interstellar plasma delays each channel by 4.149 ms times DM times (1/f^2 - 1/f_top^2), with f in GHz and DM, the dispersion measure, around 60. Generate each new sample as the pulse at that delayed time plus Gaussian noise.
- Draw a waterfall: frequency on the vertical axis (high at the top), time across, written into an ImageData buffer and scaled up with drawImage. Use a dark-purple-to-yellow colormap. The pulses should appear as curved sweeps.
- Add a DM slider. Before drawing, shift each channel back by the delay for the slider's DM. At the right value the sweeps become vertical lines.
Once that works, make it beautiful:
- Under the waterfall, plot the sum across all channels. It is smeared at the wrong DM and spikes at the right one.
- Compute the signal-to-noise of that sum for every trial DM from 0 to 160 (a few per frame) and plot it, so the visitor can see the peak. Divide the peak DM by 0.03 electrons per cubic centimeter to estimate the distance in parsecs.
- Add realism: one or two channels with constant interference, and an occasional burst that hits all channels at once (it is upright at DM 0, which is how real searches spot it).
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 spinning 3D neutron star whose beam geometry sets the pulse shape, scattering tails at low frequency, or turning each pulse into a sound that sweeps down in pitch when it is dispersed.