What this tool does

The Raycast Visualizer is an interactive demo of 2D visibility-polygon computation, the algorithm behind line-of-sight in stealth games, light propagation in 2D engines, and "what can a guard see from this corner" puzzles. Move the pointer over the canvas and the tool casts rays from that point, finds where each one first hits a wall, and fills the polygon of everything visible.

It's not a finished engine; it's a teaching surface. Three preset scenes (rooms, pillars, diagonals) exercise different geometric edge cases.

How the algorithm works

For every line-segment wall in the scene:

1. Cast a ray from the light toward each wall's two endpoints. That alone gives you the silhouette of obstacles. 2. Cast ±epsilon extra rays on each side of every endpoint. This is the trick, without the spread, the ray exactly hits the corner and the polygon would have nothing to wrap around the wall behind it. The two extra rays "peek around the corner" and continue until they hit the next wall. 3. Optionally cast N fill rays at evenly spaced angles. These don't change correctness, the endpoint rays already define the polygon, but they give the polygon-fill mode smoother edges in render mode. 4. Sort all hits by angle around the light, and you have the visibility polygon as a closed loop.

The whole computation is O((W + F) · W) per frame where W is wall count and F is fill rays. For the built-in scenes that's a few hundred segment intersections per pointer move, trivial on any modern machine.

Reading the canvas

  • Light source, the small dot at the pointer position.
  • Walls, black line segments. Toggle visibility with the "Show walls" switch.
  • Polygon mode, the visible region is filled with a radial gradient from light to dark. This is the gameplay-style render.
  • Ray-line mode, every cast ray is drawn as a faint line. This is the debug-style render that makes the algorithm legible.
  • Stats overlay, top-right corner shows ray count, frame milliseconds, and FPS. Watch how the numbers move when you change the fill-ray count.

The three preset scenes

  • Rooms, two adjacent rooms with doorways. Exercises the standard "look through an opening" case.
  • Pillars, a regular grid of small obstacles. Stresses the algorithm with many short walls and many corners.
  • Diagonals, a sparse set of non-axis-aligned walls. Makes diagonal-corner peek artefacts obvious if your epsilon spread is too tight.

Reduced-motion mode

If your OS has prefers-reduced-motion: reduce set, the visualizer switches to snapshot mode, it draws the polygon only when the pointer moves, not in a continuous animation loop. The algorithm is identical; only the render schedule changes. The "Reduced motion" badge appears at the top so you know it's active.

Common questions about the math

  • Why epsilon rays and not exact endpoint rays? An exact endpoint ray ends at the corner. The polygon vertex is at that exact point, and the polygon would have no width to wrap around the wall extending past the corner. Two ε-offset rays continue past the corner into the next gap, giving the polygon two extra vertices to wrap around.
  • What happens with overlapping walls? Each ray reports its closest hit, so an inner wall always occludes a wall behind it. There's no Z-buffering needed, line-segment intersection naturally ranks by t.
  • Why doesn't the polygon close cleanly sometimes? If your fill-ray count is 0 and the scene has very long walls between adjacent corners, the polygon edge between two endpoint hits is a straight line, fine for short walls, visibly faceted for long ones. Increase fill rays to smooth.

Privacy

Everything, the scene data, the math, the rendering, runs in your browser on a <canvas>. There are no network requests during interaction. The PNG export is a local canvas.toBlob download. No data leaves the page.

Frequently asked

Does this tool talk to a server?

No. The geometry, ray-casting math, and canvas rendering all run in your browser tab. The PNG export is a local canvas.toBlob download. No network requests are made during interaction.

What's the visibility polygon used for in real software?

Stealth games use it for guard line-of-sight, top-down shooters use it for fog-of-war, 2D lighting engines use it for soft-shadow falloff, and roguelike fov (field-of-view) systems use a discretized version. The algorithm shown here is the canonical continuous-geometry version.

Why are there extra rays at every wall corner?

Each wall endpoint gets three rays: one exactly at the corner, and two with a tiny angular offset. The offset rays 'peek past' the corner so the polygon can wrap around walls that extend beyond it. Without them, the polygon would clip flush at every corner and miss visible space behind.

What does the 'fill rays' slider actually do?

It adds N evenly-spaced rays in addition to the wall-endpoint rays. The endpoint rays alone are enough for a correct polygon, but in polygon-fill render mode the gradient looks faceted between widely-spaced corners. Fill rays smooth that out at the cost of frame time.

Why does the canvas freeze when prefers-reduced-motion is on?

It doesn't freeze — it switches to snapshot mode. The algorithm runs once per pointer-move event instead of every animation frame. This avoids the continuous flickering some users find triggering. Move the pointer to update.

How fast is this on real hardware?

For the built-in scenes (16–48 walls), each frame is a few hundred ray-segment intersections. On a modern laptop CPU that's well under a millisecond — the canvas DPR scaling and gradient fill take longer than the geometry. For 1000+ walls you'd want a spatial index (BVH or quadtree) instead of brute force.

Can I add my own scene?

Not via the UI — the three preset scenes are hard-coded line-segment arrays. To add a custom scene, edit the SCENES object in raycast-visualizer.jsx. Each segment is { x1, y1, x2, y2 } in a 1000×640 canvas-space coordinate system.

What does the PNG export contain?

A snapshot of the current canvas frame at the device pixel ratio of your display. It captures whatever's visible — walls, polygon fill or ray lines, the light dot — but not the stats overlay (the overlay is HTML, not canvas pixels). The file is a local download; no server touches it.