Skip to content

Getting started ​

dungeonmaker-js generates procedural dungeons in JavaScript. It is an unofficial WebAssembly port of DungeonMaker 2.05 by Peter Henningsen (with contributions by Aaron Dalton), the C++ generator written in 2001 (copyright 2001 Dr. Peter Henningsen) and released as 2.05 in 2005. The package compiles the original generator to WebAssembly, runs it in a Web Worker and wraps it in a typed API, a set of renderers and exporters, and a command line tool. The same design and seed always produce the same dungeon, on every platform.

The package is released under GPL-3.0-or-later; read License before you ship it inside an application. Want to see it first? The Playground generates dungeons in your browser.

Install ​

sh
pnpm add dungeonmaker-js
sh
npm install dungeonmaker-js
sh
yarn add dungeonmaker-js
sh
bun add dungeonmaker-js

The package is ESM only. Its entries are:

  • dungeonmaker-js: client and design helpers
  • dungeonmaker-js/presets: the eleven upstream designs as JSON
  • dungeonmaker-js/schema: validateDesign and the TypeBox schema
  • dungeonmaker-js/core: the bare WebAssembly core (loadCore()), takes legacy design text
  • dungeonmaker-js/worker: the worker module, for the worker escape hatch
  • dungeonmaker-js/render: ASCII, tiles, RGBA, canvas
  • dungeonmaker-js/export: dungeon JSON, PNG, Tiled .tmj, ASCII, raw
  • dungeonmaker-js/node: generateToFiles, Node only
  • dungeonmaker-js/design.schema.json and dungeonmaker-js/dungeon.schema.json: the JSON Schemas of the design and the dungeon file

Quick start (browser) ​

js
import { createDungeon } from 'dungeonmaker-js';
import { design3A } from 'dungeonmaker-js/presets';

const dungeon = await createDungeon({ design: design3A, seed: 42 });
// dungeon.width, dungeon.height, dungeon.cells (Uint8Array, row-major), dungeon.get(x, y)

createDungeon runs the generator in a Web Worker, so the page stays responsive. The worker and the wasm file are found through new URL(…, import.meta.url); Vite and webpack 5 need no configuration (see Bundlers). More on the client in Worker client.

Quick start (CLI) ​

sh
pnpm dlx dungeonmaker-js generate --preset design3A --seed 42 --format json,png --out ./dungeons
sh
npx dungeonmaker-js generate --preset design3A --seed 42 --format json,png --out ./dungeons
sh
yarn dlx dungeonmaker-js generate --preset design3A --seed 42 --format json,png --out ./dungeons
sh
bunx dungeonmaker-js generate --preset design3A --seed 42 --format json,png --out ./dungeons

This writes design3A-42.dungeon.json and design3A-42.png into ./dungeons. All commands and options are listed in Command line.

Example (Node) ​

js
import { readFile } from 'node:fs/promises';
import { loadCore } from 'dungeonmaker-js/core';

const core = await loadCore();
const design = await readFile('my-design.txt', 'utf8'); // DungeonMaker design text
const { width, height, cells } = core.generate(design, 42);
// cells: Uint8Array, row-major, north-up: cells[y * width + x]

The same design text and seed always produce the same dungeon, on every platform.

JSON designs and presets ​

js
import { extendDesign, toDesignText } from 'dungeonmaker-js';
import { loadCore } from 'dungeonmaker-js/core';
import * as presets from 'dungeonmaker-js/presets';

const design = extendDesign(presets.designEmpty, { map: { width: 80, height: 60 } });
const core = await loadCore();
const { width, height, cells } = core.generate(toDesignText(design), 42);

The presets are shared objects: derive variants with extendDesign, never mutate a preset. toDesignText throws a DesignValidationError (with a JSON Pointer per issue) for a design the generator cannot run, for example rooms or builders that fall outside a smaller map.

Add "$schema": "https://unpkg.com/dungeonmaker-js/design.schema.json" to a JSON design for editor autocomplete and validation; validateDesign from dungeonmaker-js/schema checks a design at runtime. Old design files are read with parseDesignText. Every field is listed in the design config reference; the ideas behind them are in Design concepts.

Bundlers ​

Vite (build and dev) and webpack 5 (--mode production) build the client without configuration; pnpm bundler:smoke in the repository verifies this against the packed tarball. webpack 5 production builds print a size hint for the ~264 KiB wasm file (~90 KiB gzip); it is harmless, and performance.assetFilter silences it.

If your bundler cannot resolve the worker or the wasm file, pass them explicitly:

js
const maker = createDungeonMaker({
  wasmUrl: '/assets/dungeonmaker.wasm', // the file at `dungeonmaker-js/dungeonmaker.wasm`
  worker: () => new Worker(new URL('./dm-worker.js', import.meta.url), { type: 'module' }),
});

with dm-worker.js containing only

js
import 'dungeonmaker-js/worker';

Content Security Policy ​

A strict policy works with these directives:

Content-Security-Policy: default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'

'wasm-unsafe-eval' is required because the worker calls WebAssembly.compile. The worker script and the wasm file must be served from your own origin; worker-src covers the worker.

Where to go next ​

DungeonMaker 2.05 © Peter Henningsen. WebAssembly port, package and site created by spearwolf. Released under GPL-3.0-or-later. About · License