Six-Room Dungeon Diagram Generator, based on BSD by Traverse Fantasy
Based on Bite-Sized Dungeons by Marcia B.
Clicking the button below generates a dungeon; randomizes its contents, connections, and entrance(s); and displays it as a mermaid diagram.
This could surely be improved by someone with more knowledge of javascript and mermaid.js, but I’ve been using Marcia’s method since the original blog post to create dungeons and I wanted to make a generator for it for my personal use.
In the future, I’ll probably replace the text with some fun icons, and maybe I can add an option to layer up to three dungeons together. I usually use two or three bite-sized dungeons to make a single one for my home game. Maybe I could also add some capability to download the output SVG as a PNG. (That’s done thanks to this Stackoverflow answer). Also I was only able to get to this to work in Mermaid 7. Mermaid is very finnicky to work with it turns out, at least for me.
Select to reveal Javascript
/// stuff I took from stackoverflow to make this work, only works in mermaid 7 const appendDiagramTo = (el) => (code) => el.outerHTML = code function renderDiagram(id, el) { mermaid.render( id, el.textContent, appendDiagramTo(el) ) } // randomizing and sorting stuff const sortAlphaNum = (a, b) => a.localeCompare(b, 'en', { numeric: true }); // for alphanumerically sorting the rooms function getRandomInt(max) { return Math.floor(Math.random() * max); // random number function }; // there is probably quite a bit more splicing and dicing of arrays that was completely necessary. I'm sure this could have been simpler to do function dngngn() { //all of our rooms var rooms = [1,2,3,4,5,6]; //extract and define the monster rooms separately var monsterRoom = rooms.splice(getRandomInt(6),1) + " Monster"; var monsterTreasureRoom = rooms.splice(getRandomInt(5),1) + " Monster & Treasure"; //extract the interactive room from the rest of the remaining empty rooms var interactiveRoom = rooms.splice(getRandomInt(4),1) + " Interactive"; // define the empty rooms in a single array, in order of treasure room + 2 empty rooms var emptyRooms = [rooms.splice(getRandomInt(3),1) + " Treasure", rooms.splice(getRandomInt(2),1) + " Empty Room", rooms.splice(getRandomInt(1),1) + " Empty"]; // lay a trap in one of the empty rooms var trapRoom = [emptyRooms.splice(getRandomInt(3),1) + ", Trapped"]; // regroup the rooms array back into all of the rooms and flatten them out rooms = [interactiveRoom, monsterTreasureRoom, monsterRoom, trapRoom, emptyRooms].flat(); // find your entrances: this was weirdly more complicated than I thought it would be. Maybe there was an easier way var entrances = []; var b = getRandomInt(2) + 1; // randomize whether there are 1 or 2 entrances var n = 6; // define the number six. I promise, it matters. for (b; b > 0; b--){ entrances.push(rooms.splice(getRandomInt(n),1) + ", Entrance"); if (b == 2) { n--; // basically, if there are 2 entrances, the second time you go around this loop, you want to reduce the numbers you randomize through to 5 (subtract 1 from n). But if there is only 1 entrance, you still want n to be 6 from the beginning. So that's why I defined n as 6. Is there a simpler way? } } var dungeon = rooms.concat(entrances).sort(sortAlphaNum); // put all the rooms in one array, ordered 1-6 for (var i = 0; i < dungeon.length; i++) { dungeon[i] = i + 1 + "((" + dungeon[i] + "))"; // add the proper formatting for the mermaid graph } var passages = ["|long hall|", "|stuck/locked door|", "|secret door|", "|short hall or door|", "|short hall or door|", "|short hall or door|"]; // here are all the connections with the proper mermaid formatting // what follows is a complete list of all 13 BSD configurations written in mermaid. Each room is already randomized and the passages in between are randomized const dungeonLayouts = [ dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n", dungeon[1-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n" +dungeon[2-1] + "---" + passages[getRandomInt(6)] + dungeon[3-1] + "\n" +dungeon[3-1] + "---" + passages[getRandomInt(6)] + dungeon[4-1] + "\n" +dungeon[4-1] + "---" + passages[getRandomInt(6)] + dungeon[5-1] + "\n" +dungeon[5-1] + "---" + passages[getRandomInt(6)] + dungeon[6-1] + "\n" +dungeon[6-1] + "---" + passages[getRandomInt(6)] + dungeon[2-1] + "\n", ]; var mermaidDiagramContainer = document.querySelector('#mermaid'); return ` \<pre class="mermaid"\> graph TD ` + dungeonLayouts[getRandomInt(13)] + `\<\/pre\>`; }; $(".add-diagram").on("click", function() { $("#output").html(dngngn()); $("pre.mermaid").each(function(i, e) { // creating the container ID -> this is NOT unique, so if you have // multiple places on your page rendering multiple diagrams, you // should update this to be really unique const containerId = `mermaid-${i}`; // rendering the diagram with the unique ID renderDiagram(containerId, e); }); // activates convert to png button const serializeAsXML = $e => (new XMLSerializer()).serializeToString($e) const encodeAsUTF8 = s => `${dataHeader},${encodeURIComponent(s)}` const encodeAsB64 = s => `${dataHeader};base64,${btoa(s)}` const convertSVGtoImg = async e => { const $btn = e.target const format = $btn.dataset.format ?? 'png' // $label.textContent = format destroyChildren($holder) const svgData = encodeAsUTF8(serializeAsXML($svg)) const img = await loadImage(svgData) const $canvas = document.createElement('canvas') $canvas.width = $svg.clientWidth $canvas.height = $svg.clientHeight $canvas.getContext('2d').drawImage(img, 0, 0, $svg.clientWidth, $svg.clientHeight) const dataURL = await $canvas.toDataURL(`image/${format}`, 1.0) console.log(dataURL) const $img = document.createElement('img') $img.src = dataURL $holder.appendChild($img) } const buttons = [...document.querySelectorAll('[data-format]')] for (const $btn of buttons) { $btn.onclick = convertSVGtoImg } })
- Next Post: EPUBs for TTRPG Adventures
All Posts
- 2024 December 13 The Witch-Finder, Monster and Background
- 2024 December 06 4 Merchants You Meet on the Road
- 2024 November 29 Neither a Borrower or Lender Be
- 2024 June 28 Yes Chef! Chef background for Cairn 2e
- 2024 April 28 Weather Hex Flower App for Dolmenwood
- 2024 March 30 Hexer Background for Cairn 2e
- 2024 March 22 EPUBs for TTRPG Adventures
- 2024 January 16 Six-Room Dungeon Diagram Generator, based on BSD by Traverse Fantasy