A spinning lidar maps a forest point by point, with ICP SLAM fixing its drift.
A rover carries a spinning lidar with 16 to 128 lasers through a forest clearing or a warehouse, firing 2,048 columns per turn. Every beam is a real ray cast against the scene (a terrain height field solved by secant steps, cylinders, ellipsoids and oriented boxes, culled by one degree azimuth bins), and canopies are participating media where each beam samples an exponential free path, so trees return fuzzy, layered clouds. Beam divergence, range noise, intensity from reflectivity, incidence and falloff, and dropouts of weak returns give the ghostly rings and occlusion shadows of a real scan. The rover only knows its pose from odometry with a gyro bias and a wheel scale error, so after every turn the sweep is registered against the map with 2D point-to-point ICP over a spatial hash, which corrects the pose and learns the gyro bias online; switch SLAM off and the map smears into ghost walls while the mini map shows both trajectories drift apart.
Try it. Drag to orbit, scroll (or + and -) to zoom, and click the ground to send the rover there. Pick 16, 32, 64 or 128 beams (keys 1 to 4), cycle coloring by range, height, intensity or laser ring (C), toggle SLAM (S), switch between the forest and the warehouse (W), clear the map (R), and pause the rover with Space.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a simulated spinning lidar scanner 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, with a near-black background.
- Describe a small scene in code: a flat ground plane, a dozen vertical cylinders (tree trunks), a few spheres (rocks) and a couple of axis-aligned boxes (a shed and a car). Write ray intersection functions for a plane, a cylinder, a sphere and a box.
- Put a sensor 1.8 meters above the ground with 16 lasers spread in elevation from -15 to +15 degrees. Each frame, advance its rotation by a few degrees and cast one ray per laser for each new azimuth step. Keep the nearest hit within 60 meters.
- Store every hit as a 3D point (up to a few hundred thousand) and draw them all as 1 pixel dots with an orbiting perspective camera, colored by distance from the sensor.
- You should already see rings on the ground and dark shadows behind every object.
Once that works, make it beautiful:
- Add a little range noise and a tiny random tilt to each beam, and drop weak returns from far away.
- Draw the points additively into a float buffer and tone map it with 1 - exp(-x), so dense areas glow.
- Drive the sensor slowly around a loop so the cloud fills in, and draw the live laser fan as faint red lines.
- Let me drag to orbit and switch between 16, 32 and 64 lasers.
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 treating tree canopies as a fuzzy medium, adding odometry drift and fixing it with ICP scan matching, or coloring points by return intensity.