A real ray tracer where every pixel is an identical empty <div> and the CSS engine does all the math. No JavaScript, no canvas, no SVG, no images, no per-pixel data. The stylesheet is the shader.
Open index.html → the sun orbits live, with shadows and reflections.
Since CSS got sin() and sqrt(), people have noted that "in theory you could write a raytracer in pure CSS." Then Chrome 138 (June 2025) shipped sibling-index() — a div can now ask which child am I from inside the stylesheet. That's a fragment coordinate. That's gl_FragCoord with its tail wagging.
The markup here carries no information. 5,184 identical empty divs in a grid. Each derives its pixel coordinate from its own index, builds a camera ray, intersects two spheres and a floor plane, casts real shadow rays at the sun, bounces one reflection off the mirror sphere, and paints itself with a single rgb(). One CSS animation drives the sun; the engine re-raytraces the whole scene every frame. ~460,000 calc() evaluations per frame, because I asked nicely.
git clone https://github.com/Metrix187/pawtracedOpen index.html. That's it.
Requires Chrome/Edge 138+ or Safari 26.2+ (sibling-index() is the whole trick). Firefox hasn't shipped it in stable yet (expected ~145); the page shows a soft warning there instead of a black rectangle. Expect mild CPU warmth — it's a raytracer doing its best.
sibling-index()is the fragment coordinate.mod()+ a divide turn one integer into (x, y). No attributes, no inline styles, no nth-child spaghetti.- Registered custom properties are float registers.
@property … syntax: "<number>"— load-bearing. Registered properties resolve to an actual number at each step; unregistered ones double as raw token soup until the substitution cap eats your homework. - No branches, only masks.
clamp(0, x * 100000, 1)is a step function. Hit-or-miss, nearest-surface, shadow occlusion — all arithmetic on 0/1 masks. - One animated number is the scene uniform.
@keyframesdrives--T; sun azimuth, light vector, shadows, speculars, and sky glow all re-derive from it per frame.
generate.ps1 and mandelbrot.ps1 emit the HTML files (they exist to scaffold the divs — nothing runs at page load except the CSS engine). Tweak scene constants at the top of the shader block and re-run:
.\generate.ps1
.\mandelbrot.ps1mandelbrot.html — 14,400 divs, 50 unrolled iterations of z = z² + c in calc(), colored by escape time in oklch. Same rules: zero JS, zero per-pixel data.
The closest is U2RE-Dev's CSS-ray-tracer — genuine calc-chain math, worth reading. But pixels there carry x/y SVG attributes, CSS is SCSS-prebuilt and JS-injected, light is static, and there are no shadow rays. This version uses dumb uniform markup, an animated light, real shadows, and only portable math. Full notes and paper trail in notes.md.
Complete. The scene is fixed; extend it by editing scene constants and re-running generate.ps1.
WTFPUP — do what the fuck you want to, pup ♡

