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.
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



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"andaria-labelon the canvas. As a decorative background or as an indicator next to a text, switch it toaria-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
hiddenattribute 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.
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):
<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 / property | Default | Effect |
|---|---|---|
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
newMaze() (for instance grid[0].walls[3] = false;), but the solution is neither computed nor shown.PAUSE to Infinity. The last maze stays displayed and the loop simply keeps redrawing it. Resizing the area still starts a new one.