Sundogs, arcs and halos built up live from millions of rays traced through ice.
Each sunbeam meets one hexagonal ice prism drawn from the current mix of crystals: plates that float face down, columns lying sideways, Parry columns that also keep two faces level, and tumbling crystals in random orientations. It enters a face picked in proportion to the area that face shows the sun, then Fresnel's equations decide at every surface whether it reflects or escapes, Snell's law with ice's wavelength-dependent index bends it on the way out, and total internal reflection traps it when it must. Exit directions carry their wavelength's color into a floating point sky seen through a fisheye lens, about a million rays a second. The 22 and 46 degree halos, sundogs, circumzenithal arc, parhelic circle, tangent arcs and Parry arcs all emerge from that one procedure, and change shape as the sun moves.
Try it. Drag up or down to raise or lower the sun and the sky rebuilds from nothing. Use the sliders to mix plates, columns, Parry columns and random crystals, press 1 to 5 for classic displays, L to hide the labels and R to restart the accumulation.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build an ice crystal halo 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 and stays sharp on high-DPI screens. Keep a Float32Array accumulation buffer at about half resolution, plus a count of rays traced.
- Model one crystal as a hexagonal prism: six side planes n . p = 1 with normals every 60 degrees around the z axis, and two end planes at z = +h and -h.
- For each ray: pick a uniformly random crystal orientation (a random unit quaternion), rotate the sun's direction into the crystal's frame, choose an entry face weighted by its area times how squarely it faces the sun, refract in with Snell's law (n = 1.31), then repeatedly find the nearest plane ahead, and reflect (if total internal reflection) or refract out. Cap it at about 10 bounces.
- Turn the exit direction into a point on the screen (an equidistant fisheye centered on the sky above the sun works well) and add 1 to that pixel. Trace about 20,000 rays per frame and display the buffer scaled by the ray count over a deep blue sky. A 22 degree halo should appear around the sun.
Once that works, make it beautiful:
- Give each ray a random wavelength with its own refractive index and color, so the halo gets a red inner edge.
- Add Fresnel's equations: at each face reflect with probability R, otherwise refract.
- Add oriented crystals: flat plates whose axis stays near vertical make sundogs and the circumzenithal arc, and columns lying sideways make tangent arcs.
- Let dragging up and down move the sun, clearing the buffer each time, and add sliders for the crystal mix.
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 Parry-oriented columns, labeling each arc by name, or a 3D view of a single crystal with its ray paths.