A long exposure builds over a mountain camp as the sky wheels around the celestial pole.
About 11,000 stars sit on the celestial sphere: the brightest hundred from a catalogue with their real colours, the rest generated with true magnitude counts and crowded toward the Milky Way, plus both Magellanic Clouds. Earth's rotation, the latitude and the camera's aim fold into one matrix per sub-step, and an equidistant fisheye lens (a 140 degree field) maps each star onto a floating point sensor, where it deposits flux times time into four pixels by bilinear splatting, dimmed by airmass near the horizon and coloured by a blackbody fit to its B-V index. Sub-steps are sized so no star moves more than half a pixel between deposits, and the exposure fades slowly like a stacked comet-style frame. The developed image is a tone curve over airglow and town glow, with ridges from layered noise, a lantern-lit tent, aircraft strobes, meteors, film grain and vignetting.
Try it. Drag the latitude slider to move the pole from the horizon to the zenith and across to the south. Use N, E, S and W (buttons or keys) to face a direction: toward the equator the trails straighten into diagonal lines. Drag the sky to re-aim the camera, click it to send a meteor, press P for an aircraft, up and down step the latitude, space pauses the exposure.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a long-exposure star trail photograph that develops as you watch, 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.
- Scatter a few thousand stars uniformly over a sphere as unit vectors in equatorial coordinates, with magnitudes skewed toward faint ones. Brightness is 10 to the power of minus 0.4 times the magnitude.
- Each frame, advance the sidereal time, rotate every star about the celestial pole, then into the horizon frame for a latitude of 45 degrees, and project the ones above the horizon with a simple fisheye: the pixel distance from the image centre is proportional to the angle from the direction the camera points.
- Keep a Float32Array exposure buffer the size of a downscaled canvas. Add each star's brightness into the four pixels around it (bilinear splatting) every frame instead of drawing it, then map the buffer through a tone curve such as x / (x + 1) into an ImageData and draw it scaled up.
Once that works, make it beautiful:
- Take enough sub-steps per frame that no star moves more than half a pixel between deposits, so trails stay continuous.
- Colour stars with a blackbody tint from a B-V index, dim them near the horizon, and paint a dark blue sky with a faint green airglow band behind the trails.
- Add a mountain silhouette from layered noise, a small glowing tent in the foreground, film grain and a vignette.
- Add a latitude slider and north, east, south and west buttons, and fade the buffer quickly whenever the view changes.
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 real bright stars, aircraft strobe trails and meteors, or a slow fade that turns the trails into comets.