Select an image from the gallery to preview
No images uploaded yet. Click "Select Images" to get started.
The Image to Maze Generator works by sampling your uploaded image into a grid of brightness values. Each cell in that grid is assigned a "resolution" — a number of tiny internal nodes — based on how dark or light the corresponding part of the image is. Darker areas get more nodes, creating finer, denser passages, while lighter areas get fewer nodes, resulting in wider, more open paths. This is controlled by the Min resolution, Max resolution, and Contrast sliders, along with the Invert source checkbox.
Once every cell has its internal node grid, the code connects neighboring nodes — both within a cell and across cell boundaries — to form a single, large graph. A randomized depth-first search (DFS) then carves a spanning tree through that graph, guaranteeing that every node is reachable and that there is exactly one path between any two points. The entrance is always the top-left node of the first cell, and the exit is the bottom-right node of the last cell. This approach is a direct adaptation of classic maze-generation techniques described in resources like [Wikipedia, Maze generation algorithm] and [Jamis Buck, Maze Algorithms].
The Min resolution and Max resolution values define how many nodes are packed into each cell at the darkest and lightest extremes. A low minimum (like 1) means bright areas become single, wide-open nodes; a high maximum (like 7) means dark areas are subdivided into a 7×7 grid of tiny nodes, producing intricate, tight corridors. The Contrast slider stretches or compresses the brightness range before resolution is calculated, letting you exaggerate or soften the image's influence on the maze structure.
Because the graph is built with a fixed seed, the same image and settings will always produce the same maze. Clicking New Layout generates a fresh random seed, reshuffling the DFS traversal order and giving you a completely different set of corridors — even though the underlying graph and image influence remain identical. This deterministic-yet-variable behavior is a hallmark of pseudorandom number generators like the mulberry32 function used in the code, a technique well documented in [Bryc, PRNGs] and [Stack Overflow, Seeding PRNGs].
When Use colors is active (the default), each edge in the maze is drawn using a color sampled from the corresponding region of the original image. The code quantizes those colors to a 16-step palette and adjusts their luminance to keep them readable against the background. This means your maze isn't just structurally inspired by the image — it's literally painted with the image's own colors. The result is a maze that feels like a stylized, line-art version of your photo, similar to the aesthetic principles explored in [Wikipedia, Photomosaic].
The maze carving uses a randomized depth-first search, often called "recursive backtracking" in maze literature. The algorithm starts at the entrance, marks the current node as visited, and repeatedly moves to a random unvisited neighbor. When it reaches a dead end, it backtracks to the last node with unvisited neighbors. Every time it moves to a new node, it records the edge in a treeEdges array — these become the walls of the maze. The result is a spanning tree: a connected graph with no cycles, which is exactly what makes a "perfect" maze where every point is reachable and there's only one path between any two points.
This method is one of the oldest and most reliable maze algorithms. For more information, see [Wikipedia, Randomized depth-first search]. Its main drawback is that it produces long, winding corridors with relatively few short dead ends, which is why the generator offers multiple presets — by varying the resolution and contrast, you can shift the balance between sprawling passages and tight, intricate dead ends.
Because the carving process uses DFS, the parent array it builds along the way is itself a complete solution map. Each node's parent is the node from which it was first discovered during the DFS traversal. To find the solution path from entrance to exit, the code simply follows the parent links backward from the exit node until it reaches the entrance, then reverses the resulting edge list. This is the same parent-pointer technique used in graph theory to reconstruct shortest paths in trees, and it's explained in resources like [Wikipedia, Depth-first search] and [GeeksforGeeks, DFS for a Graph].
The Solved preview tab overlays this solution path in the chosen solution color (default #c04e32, a warm ember tone). You can change it using the color picker in the Maze Options panel. The solution line is drawn on top of the maze walls, so it's easy to trace the correct route from the entrance circle to the exit circle.
One of the trickier parts of the generator is joining cells that have different internal resolutions. If a 1×1 cell sits next to a 7×7 cell, how do you connect their boundaries? The code uses a proportional mapping: it divides each boundary into evenly spaced sample points and connects each point to the closest corresponding point on the neighboring boundary. This ensures that every boundary node has at least one connection across, so the maze remains fully connected even when resolution changes dramatically from one cell to the next.
This boundary-matching approach is similar to techniques used in adaptive mesh refinement and quadtree-based maze generation, where cells of different sizes must share edges. For more on these ideas, see [Wikipedia, Quadtree] and [ScienceDirect, Adaptive Mesh Refinement].
Mazes have fascinated humans for thousands of years. The earliest known maze-like structures date back to ancient Egypt and Greece, with the legendary Labyrinth of Crete being one of the most famous. In the Middle Ages, mazes became a feature of European cathedrals, where they were walked as acts of pilgrimage. Today, mazes appear in everything from garden design to video games, and they remain a powerful metaphor for confusion, discovery, and problem-solving. The [Wikipedia, Labyrinth] article provides a comprehensive overview of their history and cultural significance.
Modern algorithmic mazes, like the ones generated here, are part of a tradition that bridges art and mathematics. They're used in computer science education to teach graph theory and recursion, in psychology to study spatial reasoning, and in generative art as a way to transform images into interactive, playable structures. The [Wikipedia, Maze] article covers both historical and computational aspects.
Turning an image into a maze is a form of generative art — art created through a set of rules or algorithms. The image acts as a "seed" that guides the algorithm's decisions, but the final output is always a unique, unpredictable structure. This interplay between order and randomness is central to many generative art practices, as explored in [Wikipedia, Generative art].
The generator also uses a technique called "dithering" in its color sampling — reducing the number of colors and quantizing them to a fixed palette. This gives the output a screen-printed, retro feel, similar to the aesthetics of [Wikipedia, Dither] and [Wikipedia, Posterization]. Combined with the maze structure, the result is a striking visual that's both a puzzle and a piece of algorithmic art.
Beyond art, this generator can be used to create custom puzzles for classrooms, escape rooms, or games. Teachers can turn historical photos or diagrams into mazes to spark curiosity. Artists can use the output as a starting point for further digital manipulation. Developers can study the code to learn about graph construction, DFS traversal, and canvas rendering — all of which are fundamental skills in computer graphics and game development.
The code is intentionally modular: buildGraph handles graph construction, carveMaze performs the DFS, solvePath reconstructs the solution, and drawMaze renders everything to canvas. Each function is small, focused, and documented with comments, making it a good reference for anyone learning how to combine image processing with algorithmic generation. For further reading on canvas rendering and image manipulation, see [MDN, Canvas API] and [MDN, Pixel Manipulation].