Snippet

Maze generation

Full page view

Description

Uses the recursive backtracker algorithm to generate a maze with SVG.

Created on 4 June 2026.

Code

<svg stroke='#fff'>
  <circle r='200%'/>
</svg>

<script>
  const SVG_NS = 'http://www.w3.org/2000/svg';

  const svg = document.querySelector('svg');

  const cellSize = 20, // in pixels
    pathWidth = 0.8,
    width = Math.floor(innerWidth / cellSize),
    height = Math.floor(innerHeight / cellSize);

  // Set up SVG
  svg.setAttribute('viewBox', [ -.6, -.6, width + .2, height + .2 ]);
  svg.setAttribute('stroke-width', pathWidth);

  // Maze variables
  class Cell {
    constructor(x, y) {
      this.x = x;
      this.y = y;
      this.unvisited = true;
    }
  };

  const randomInt = (max) => Math.floor(max * Math.random()),
    randomArrayItem = (array) => array[randomInt(array.length)],
    grid = Array(width).fill``.map((_, x) => Array(height).fill``.map((_, y) => new Cell(x, y))),
    stack = [ randomArrayItem(randomArrayItem(grid)) ];
    
  let pathData = '';

  // Maze generation
  while (stack.length) {
    const currentCell = stack.pop(),
      { x, y } = currentCell,
      unvisitedNeighbours = [
        grid?.[x]?.[y - 1],
        grid?.[x + 1]?.[y],
        grid?.[x]?.[y + 1],
        grid?.[x - 1]?.[y],
      ].filter(cell => cell?.unvisited);
    
    if (unvisitedNeighbours.length) {
      const chosenNeighbour = randomArrayItem(unvisitedNeighbours);
      chosenNeighbour.unvisited = false;
      stack.push(currentCell, chosenNeighbour);
      pathData += `M${[x, y, chosenNeighbour.x, chosenNeighbour.y]}v${pathWidth / 2}v-${pathWidth}`;
    }
  }

  const path = document.createElementNS(SVG_NS, 'path');
  path.setAttribute('d', pathData);
  svg.append(path);
</script>