Bent light over hot asphalt and cold sea: road puddles, floating cars, Fata Morgana.
Air bends light more when it is cooler and denser, so a hot road or a cold sea turns the atmosphere into a lens. Every row of pixels in this telephoto view is one ray, integrated through the layered air with the paraxial ray equation, Earth's curvature included. Rays that dip toward the hot asphalt curve back up and show the sky, so the road looks wet and cars float upside down in it; over cold water a warm layer aloft traps the rays, stretching ships beyond the horizon into towers and slicing the setting sun. Cars, poles, mesas and ships are billboards sampled at the height each ray reaches at their distance, and the panel below draws the same rays with heights exaggerated a few hundred times.
Try it. Drag the slider to heat or cool the air at the surface, and drag up or down on the view to raise or lower your eye. Hover the view to highlight that row's ray in the diagram. Switch between the desert road and the cold sea, or use the arrow keys, 1 and 2, and Space to send a car.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a mirage simulator 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, and resizes with the window.
- Model the air above a hot road: temperature T(h) = Tair + dT * exp(-h / 0.1), with h in meters. The refractive index is n(h) = 1 + 7.76e-5 * 1013 / T(h). Tabulate dn/dh on a fine grid.
- Treat each row of a small offscreen canvas (about 320 by 200) as one ray leaving an eye 1.5 m above the road, with an elevation angle spanning about +0.3 to -0.6 degrees. Integrate h'' = dn/dh with small steps (smaller near the ground) out to a few kilometers.
- If the ray hits the ground, color the pixel as asphalt or sand from where it landed (x distance, and the column's angle times x for the sideways position). If it escapes, color it as sky from its final angle.
- drawImage the offscreen canvas scaled up to fill the screen.
Once that works, make it beautiful:
- Add a slider for dT and watch the far road turn into a silver 'lake' that reflects the sky.
- Put a car on the road as a flat billboard at some distance: each row checks the height its ray reaches at that distance and samples the car there. Inverted cars appear in the 'water' for free.
- Draw the rays themselves in a panel below, as thin translucent curves with the heights exaggerated a few hundred times.
- Add a gentle shimmer by wobbling rows that skim the hot layer with moving noise.
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 cold sea with a warm layer aloft for a Fata Morgana, adding the Earth's curvature (an extra 1/R term), or a setting sun that the mirage slices into layers.