Skip to content

Dungeon file format ​

A *.dungeon.json file is the lossless export of a generated dungeon: the cell map, optional layers (rooms, entities, generation steps) and enough metadata to reproduce it. It is written by toDungeonJson from dungeonmaker-js/export, by the generate command of the CLI and by the download menu of the playground. The format has a version (formatVersion: 1); a reader should check it before it trusts the layout.

The format is described by the JSON Schema dungeonmaker-js/dungeon.schema.json. This specification and dungeon.schema.json are released under CC0-1.0: write an importer in any language under any license.

Example ​

A shortened file for the preset design3A with seed 42 (the cells data is cut; <version> stands for the package version that wrote the file):

jsonc
{
  "format": "dungeonmaker-js/dungeon",
  "formatVersion": 1,
  "generator": "dungeonmaker-js@<version>",
  "width": 160,
  "height": 81,
  "seed": 42,
  "source": { "preset": "design3A" },
  "legend": { "0": "open", "1": "closed", "…": "…", "19": "column" },
  "cells": { "encoding": "base64", "data": "…" }
  // "rooms", "entities" and "steps" appear only when the layer was requested
}

Cells and layers ​

cells is row-major with north up: the cell at column x and row y is cells[y * width + x]. See Orientation for the axes and the meaning of the 20 cell values. The legend maps each value to a name, so a reader does not need the table.

cells comes in three encodings, chosen by the writer (cells: 'base64' | 'rows' | 'array'):

  • base64 (default): one byte per cell, base64 encoded. Compact; use it when you parse the file.
  • rows: one string per row, one character per cell, taken from the stored alphabet. It is lossless (unlike the ASCII export, which merges cells) and readable in a diff.
  • array: a plain JSON array of width * height integers.

Binary layers are base64 as well, and every multi-byte value is little-endian: rooms.roomIds is one uint16 per cell (0 = no room, otherwise the room id), steps.offsets and steps.index are uint32 arrays. steps.cell is one byte per recorded change. Entity and room positions use the same axes as cells: x is the column, y the row.

The source field ​

source says which design the dungeon came from, without copying designs that are not yours to copy:

  • A preset appears as { "preset": "<name>" }, never with its text. The CLI and generateToFiles write this form for any design whose text equals a preset, even with --embed-design.
  • Any other design appears as { "designHash": "sha256:…" }, the SHA-256 of the design text. The design itself is embedded (design) only on request.
  • A file without source makes no claim about its origin.

With the seed, the generator version and the design, a file can be reproduced byte for byte: the same version writes the same bytes.

Fields ​

FieldTypeConstraintsDefaultDescriptionUpstream
$schemastringoptional (omitted: not written by the exporters)JSON Schema URL for editor support; exporters do not emit it.
formatstring= "dungeonmaker-js/dungeon"required
formatVersionnumber= 1required
generatorstringrequireddungeonmaker-js@<version>
widthinteger≥ 0requiredMap width in cells.
heightinteger≥ 0requiredMap height in cells.
seedinteger≥ 0requiredSeed the dungeon was generated with.
sourceobjectone of 2 variantsoptional (omitted: origin not recorded)Where the design came from: a preset name, or its hash.
source{preset}.presetstringrequiredName of an upstream preset.
source{designHash}.designHashstringpattern ^sha256:[0-9a-f]{64}$requiredSHA-256 of the UTF-8 design text.
source{designHash}.designobjectoptional (omitted: design not embedded)The embedded design (see design.schema.json); only on request.
legendobjectkeys 0 … 19requiredCell value to cell name.
cellsobjectone of 3 variantsrequiredThe map, row-major, north up: index = y * width + x.
cells{base64}.encodingstring= "base64"required
cells{base64}.datastringrequiredBase64 of width * height bytes, one per cell.
cells{rows}.encodingstring= "rows"required
cells{rows}.alphabetstringrequiredOne character per cell value (index = cell); lossless.
cells{rows}.datastring[]requiredOne string of width characters per row.
cells{array}.encodingstring= "array"required
cells{array}.datainteger[]items: 0 … 19requiredwidth * height cell values, row-major.
roomsobjectoptional (omitted: layer not requested)Room id per cell (uint16 LE, base64) and the room table.
rooms.roomIdsobjectrequired
rooms.roomIds.encodingstring= "base64"required
rooms.roomIds.datastringrequiredBase64 of the little-endian bytes.
rooms.roomsobject[]required
rooms.rooms[].idinteger≥ 0requiredIndex + 1 in creation order; matches the values in roomIds.
rooms.rooms[].areastring= "labyrinth"; = "dungeon"required
rooms.rooms[].sizeinteger≥ 0requiredNumber of squares.
rooms.rooms[].boundsobjectrequired
rooms.rooms[].bounds.xinteger≥ 0requiredColumn.
rooms.rooms[].bounds.yinteger≥ 0requiredRow.
rooms.rooms[].bounds.widthinteger≥ 0requiredWidth.
rooms.rooms[].bounds.heightinteger≥ 0requiredHeight.
entitiesobject[]optional (omitted: layer not requested)MOBs, then treasure.
entities[].kindstring= "mob"; = "treasure"required
entities[].xinteger≥ 0requiredColumn.
entities[].yinteger≥ 0requiredRow.
entities[].levelinteger≥ 0requiredIndex in the design's population list.
stepsobjectoptional (omitted: layer not requested)Recorded generation steps.
steps.offsetsstringrequiredBase64 uint32 LE; frame k = index[offsets[k]..offsets[k+1]).
steps.indexstringrequiredBase64 uint32 LE; y * width + x.
steps.cellstringrequiredBase64 bytes; the cell value set at index.

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