Skip to content
wujue0115Public

About

An open-source TypeScript library for maze generation, solving, and editing.

Topics

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation


Mazely logo

Mazely

Maze generation, solving, and editing for TypeScript.

mazely on npm npm version MIT license

📚 Documentation | 🧩 Mazely Studio | 📦 npm


Mazely is a TypeScript library for generating, solving, and editing mazes. Its core exposes algorithm progress as steps. Applications can run an algorithm to completion or consume its progress incrementally to build their own visualizations, teaching tools, games, and renderers.

Features

  • Twelve maze generation algorithms and five solving algorithms
  • Deterministic generation with string or numeric seeds
  • Square, triangular, and hexagonal grids with custom masks
  • Step-by-step execution or immediate completion
  • Transactional maze editing with lifecycle events
  • JSON-safe maze serialization
  • Framework-agnostic TypeScript API with ESM support

Built with Mazely

  • Mazely Studio - an interactive maze playground for generating, solving, editing, and visualizing mazes.
  • V-CONF × Mazely - interactive 3D Vue and Vite logo mazes for V-CONF.

Packages

Package Description
mazely Recommended entry point with createMaze() defaults and the complete public API
@mazely/core Lower-level algorithms, grid model, step engine, editing, and serialization

Use mazely for applications and libraries. Reach for @mazely/core only when you are assembling a lower-level runtime directly.

Installation

pnpm add mazely
npm install mazely

For the core package directly:

pnpm add @mazely/core

Quick Start

import { createMaze } from 'mazely'

const maze = createMaze({
  grid: {
    type: 'square',
    cols: 21,
    rows: 21,
  },
  seed: 42,
})

maze.generate('dfs', {
  start: { x: 0, y: 0 },
}).finish()

maze.solve('a-star', {
  start: { x: 0, y: 0 },
  end: { x: 20, y: 20 },
}).finish()

const result = maze.getSolveResult()

console.log(result?.solved)
console.log(result?.path)
console.log(result?.visitedCount)

createMaze() defaults to a 21 x 21 square grid. Pass grid when you need explicit dimensions, a mask, or another supported topology.

Incremental Execution

Generation and solving return the same StepPlayer interface. Use next() to apply one algorithm step, prev() to revert one, reset() to return to the beginning, or finish() when only the completed result matters.

const player = maze.generate('prim')

function advance() {
  if (!player.next())
    return

  const step = player.steps[player.index - 1]
  renderMaze(maze.grid, step) // Your renderer

  requestAnimationFrame(advance) // Your scheduler
}

requestAnimationFrame(advance)

renderMaze() is application code, not a Mazely export. Each step contains grid patches and may include a payload with from and to cell IDs. Rendering, timing, pause/resume behavior, and playback controls remain under application control. player.progress.totalSteps is null while the lazy source still has unknown steps and becomes exact after completion.

Explicit Grid Configuration

import { createMaze } from 'mazely'

const maze = createMaze({
  grid: {
    type: 'square',
    rows: 31,
    cols: 31,
  },
  seed: 'repeatable-maze',
})

const generation = maze.generate('wilson')
generation.finish()

The main package also exports algorithm factories, grid types, StepPlayer, serialization helpers, seeded random utilities, and all public TypeScript types.

Triangular grids use alternating up/down cells with at most three neighbors:

const triangle = createMaze({
  grid: {
    type: 'triangle',
    layout: 'triangle',
    size: 20,
  },
  seed: 'triangles',
})

triangle.generate('prim').finish()

size is the number of smallest triangles along each side. A grid of size n contains n² cells and has a triangular outer boundary.

Triangle and hexagonal grids support Aldous-Broder, Binary Tree, DFS, Eller's, Growing Tree, Hunt-and-Kill, Kruskal, Prim, Random Traversal, Recursive Division, Sidewinder, and Wilson generation.

Use a rectangular boundary when the outer shape should remain rectangular:

const triangleRectangle = createMaze({
  grid: {
    type: 'triangle',
    layout: 'rectangle',
    rows: 20,
    cols: 40,
  },
})

Hexagonal grids have six neighbors per cell and support rectangular or hexagonal outer boundaries. Choose pointy or flat orientation:

const hexagon = createMaze({
  grid: {
    type: 'hexagon',
    layout: 'hexagon',
    size: 10,
    orientation: 'pointy',
  },
  seed: 'hexagons',
})

hexagon.generate('dfs').finish()

Use { type: 'hexagon', layout: 'rectangle', rows, cols, orientation } for a rectangular boundary. All grid types accept connected cell masks.

Algorithms

Generation

  • aldous-broder
  • binary-tree
  • dfs
  • eller
  • growing-tree
  • hunt-and-kill
  • kruskal
  • prim
  • recursive-division
  • sidewinder
  • traversal
  • wilson

Solving

  • a-star
  • best-first
  • bfs
  • dfs
  • flood (breadth-first traversal without an end point)

Masked Mazes

Pass a boolean mask to include only selected cells. Excluded cells and their edges are absent from the grid, so generation and solving stay inside the shape.

import { createMaze } from 'mazely'

const maze = createMaze({
  grid: {
    type: 'square',
    rows: 3,
    cols: 3,
    mask: [
      [true, true, true],
      [true, false, true],
      [true, true, true],
    ],
  },
})

Editing

Generated mazes can be edited without bypassing the grid model:

maze.setEdgeOpenedBetween(
  { x: 0, y: 0 },
  { x: 1, y: 0 },
  true,
)

maze.closeCell({ x: 2, y: 2 })
maze.openAllEdges()
maze.closeAllEdges()

Edit callbacks are transactional: all targets are validated before changes are committed. A thrown callback leaves the topology and lifecycle state unchanged.

Serialization

Serialize the grid topology and restore it into another compatible grid:

import {
  applySerializedGrid,
  createMaze,
  serializeGrid,
} from 'mazely'

const source = createMaze({
  grid: { type: 'square', cols: 15, rows: 15 },
  seed: 7,
})
source.generate('kruskal').finish()

const saved = serializeGrid(source.grid)
const restored = createMaze({
  grid: { type: 'square', cols: 15, rows: 15 },
})

applySerializedGrid(restored.grid, saved)

Events

const unsubscribe = maze.on('step', ({ state }) => {
  console.log(state.index, state.totalSteps)
})

maze.on('complete', ({ state }) => {
  console.log(`${state.phase} complete`)
})

unsubscribe()

Available events are step, complete, reset, phaseChange, and edit.

Development

Requirements:

  • Node.js 24
  • pnpm 10.28.0
git clone https://github.com/wujue0115/mazely.git
cd mazely
pnpm install
pnpm test:ci

Common commands:

Command Purpose
pnpm build Build all packages and applications
pnpm typecheck Type-check the complete workspace
pnpm test Run the Vitest suites
pnpm lint Run ESLint and formatting checks
pnpm test:ci Run the complete release verification

See CONTRIBUTING.md for the branching model, commit convention, and pull request checklist.

License

MIT Copyright (c) 2026-PRESENT Wujue.

About

An open-source TypeScript library for maze generation, solving, and editing.

Topics

Resources

Contributing

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages