SVG✨ Premium

Maze Generator

A maze is carved before your eyes, cell by cell, by the recursive backtracker algorithm; once finished, a new one takes its place two seconds later.

CanvasAlgorithmRecursive

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. SVG has 30 effects, including 3 free. Explore the category →

3 usage examples

Hero background for an orienteering club — Maze Generator example 1

① Hero background for an orienteering club

WhenOn the Vaulsenne Orienteering page, the maze is carved across the full width behind the headline, the "Next race" card and the sign-up button.
WhyCorridors that fork and double back evoke route choice, the heart of orienteering; the slow motion livens up the page without getting in the way of reading.
SettingsRoot in position:absolute; inset:0 with --mzg-height:100% and filter: hue-rotate(150deg) saturate(1.2) to turn violet into the club's orange without touching the script; gradient veil from 95 % to 10 % under the text; canvas set to aria-hidden="true".
Animated figure in an article explaining the algorithm — Maze Generator example 2

② Animated figure in an article explaining the algorithm

WhenOn the Cribelle blog, the article "How a computer carves a maze" describes the method and figure 1 shows it running, with a caption explaining the pink cell.
WhyText and figure say the same thing: readers watch the pink cell move forward and back while they read the paragraph, which no static diagram can show.
SettingsRoot in a 262 × 136 px block (21 × 11 cells), a complete maze in about 1.5 s followed by a 2 s pause. Canvas kept as role="img" with a label: here the figure is part of the content.
Small indicator while a hiking route is computed — Maze Generator example 3

③ Small indicator while a hiking route is computed

WhenIn the Draverne app, clicking "Plan the route" shows a 252 × 74 px strip where a maze is being carved, with "Searching trails…", until the result arrives.
WhyA path looking for its way illustrates exactly what happens during the wait, and a 20 × 6 cell maze renews fast enough to fill a few seconds.
SettingsThe waiting area is hidden (hidden) until the click; the sold code starts as soon as it has a size. The scene script only switches between the three states (idle, waiting, result).

How it works

The area is split into centred 12 px cells, each closed by four walls. The algorithm starts at the top-left cell and keeps a stack of its path: at each step it picks a random unvisited neighbour, knocks down the wall between them and moves on; when none is left, it pops the stack and backs up. When the stack is empty every cell has been visited and there is exactly one path between any two cells: a so-called "perfect" maze.

The pace is 300 steps per second, counted in elapsed time (capped at 50 ms per frame), so it is the same at 60 and 120 Hz. It takes about two steps per cell: an 800 × 300 px area (66 × 24 cells) is carved in around ten seconds. The current cell is painted pink #d946ef, carved cells in translucent violet, walls in #6366f1. Once finished, the drawing stays on screen for PAUSE milliseconds (2,000 by default), then a fresh grid starts over.

Walls are batched into a single path and carved cells into a single fill, which keeps each frame light. Size comes from the displayed area, multiplied by devicePixelRatio, and lines are offset by half a pixel to stay crisp; a ResizeObserver restarts a fitting maze when the area changes size, and nothing starts while it is smaller than one cell (closed tab or accordion). An IntersectionObserver stops the loop off screen. Every root gets its own maze, started only once (data-mzg-ready) even if the script is pasted twice.

Accessibility

  • Label: role="img" and aria-label on the canvas. As a decorative background or as an indicator next to a text, switch it to aria-hidden="true".
  • Reduced motion: under prefers-reduced-motion: reduce, the maze is carved in one go and shown finished, with no pink cell and no renewal.
  • Pausing: the animation renews endlessly. For WCAG 2.2.2, a button that toggles the root's hidden attribute stops it; it resumes at the same step.
  • Not a game: the maze cannot be walked through, with a mouse or a keyboard. Presenting it as a puzzle to solve would be misleading.
  • Keyboard: no interactive element, no focus to manage.

Browser compatibility

2D canvas and about 5.6 KB of JavaScript, no dependency. ResizeObserver: Chrome 64, Firefox 69, Safari 13.1; IntersectionObserver: Chrome 51, Firefox 55, Safari 12.1 (MDN data). Measured in Chromium 151, Firefox 153 and WebKit 26.5: no error even when the area is hidden at load, 2× density rendering, two independent mazes, finished maze under reduced motion, no frames computed off screen.

Chrome 64+✓ Full (measured)
Firefox 69+✓ Full (measured)
Safari 13.1+✓ Full (measured in WebKit)
Edge 79+✓ Full (Chromium engine)
Safari iOS 13.4+✓ Full (WebKit, not checked on a device)
Chrome Android 64+✓ Full (Chromium engine)

Without ResizeObserver, a new maze only restarts on window resize; without IntersectionObserver, carving goes on off screen. Without JavaScript, the area keeps the root's background.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0617-root">
  <canvas class="mzg-canvas" role="img" aria-label="Maze being carved out cell by cell"></canvas>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Cell size (JS — CELL) 12 px 8 px gives a fine maze that takes long to carve, 20 px wide corridors readable as a thumbnail.
Speed (JS — STEPS_PER_S) 300 steps per second 60 to follow every move of the pink cell (teaching), 1,500 for a near-instant fill.
Pause between mazes (JS — PAUSE) 2000 ms Infinity keeps the finished maze on screen without starting another.
Walls (JS — WALL) #6366f1 Any CSS colour; the line is 1 px at every screen density.
Carved cells (JS — VISITED) rgba(99, 102, 241, 0.2) transparent shows walls only, 0.4 opacity makes the travelled path stand out.
Current cell (JS — HEAD) #d946ef Colour of the carving cursor; it disappears once the maze is finished.
Whole palette (CSS — filter on the root) none hue-rotate(150deg) turns violet and pink into orange and green without editing the script.
Background and height (CSS — background and --mzg-height) #0a0a0f, 300px The canvas is transparent; height takes any fixed value or 100% inside a parent of known height.

FAQ

No opening is drawn in the frame. Since the maze is perfect, any two cells are linked by a single path: to turn it into a game you could open the outer wall of two cells by adding a line at the end of newMaze() (for instance grid[0].walls[3] = false;), but the solution is neither computed nor shown.
Yes: set PAUSE to Infinity. The last maze stays displayed and the loop simply keeps redrawing it. Resizing the area still starts a new one.
About two steps per cell at 300 steps per second: 0.8 s for 20 × 6 cells, around ten seconds for 66 × 24, plus the 2 s pause. Divide the area by four (cells twice as large) and the time drops by four.