From af315783e003f0a737bd1cc1867e26efa54bc4e0 Mon Sep 17 00:00:00 2001 From: keligrubb Date: Mon, 1 Sep 2025 16:53:37 -0400 Subject: [PATCH] cleanup everything lol --- README.md | 2 +- dungeonGenerator.js | 75 +++++++++++++++++++------------------ dungeonTemplate.js | 90 +++++++++++++++++++++++---------------------- package.json | 2 +- 4 files changed, 89 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 04c3b6b..49a0bee 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Optional: update the map path in `index.js` if you have a local dungeon map. * Three-column layout: * Column 1: Map, Adventure Hooks, Rumors - * Column 2: Keyed Rooms + * Column 2: Rooms * Column 3: Encounters, Treasure, NPCs --- diff --git a/dungeonGenerator.js b/dungeonGenerator.js index ec0083a..081a85a 100644 --- a/dungeonGenerator.js +++ b/dungeonGenerator.js @@ -62,15 +62,15 @@ async function callOllama(prompt, model = "gemma3n:e4b", retries = 5, stepName = function parseList(raw) { return raw - .split(/\n|(?=\d+[).]\s)/g) - .map(line => cleanText(line.replace(/^\d+[).\s-]*/, ""))) + .split(/\n?\d+[).]\s+/) + .map(line => cleanText(line)) .filter(Boolean); } function parseObjects(raw, type = "rooms") { return raw - .split("\n") - .map(line => cleanText(line.replace(/^\d+[).\s-]*/, ""))) + .split(/\n?\d+[).]\s+/) + .map(entry => cleanText(entry)) .filter(Boolean) .map(entry => { const [name, ...descParts] = entry.split(/[-–—:]/); @@ -97,7 +97,7 @@ Each title should come from a different style or theme. Make the set varied and - Weird fantasy: uncanny, surreal, unsettling - Whimsical: fun, quirky, playful -Avoid repeating materials or adjectives. Do not include explanations, markdown, or preambles. Only the 10 numbered titles.`, +Avoid repeating materials or adjectives. Avoid the words "obsidian" and "clockwork". Do not include explanations, markdown, or preambles. Only the 10 numbered titles.`, undefined, 5, "Step 1: Titles" ); const titles10 = parseList(titles10Raw, 30); @@ -108,7 +108,7 @@ Avoid repeating materials or adjectives. Do not include explanations, markdown, `Here are 10 dungeon titles: ${titles10.join("\n")} -Select the 3 most interesting titles from the above list and create 2 additional unique titles. +Randomly select 3 of the titles from the above list and create 2 additional unique titles. Avoid the words "obsidian" and "clockwork". Output exactly 5 titles as a numbered list, plain text only. No explanations.`, undefined, 5, "Step 2: Narrow Titles" ); @@ -117,7 +117,7 @@ Output exactly 5 titles as a numbered list, plain text only. No explanations.`, // --- Step 3: Final title --- const bestTitleRaw = await callOllama( - `From the following 5 dungeon titles, select the one that sounds the most fun to play. + `From the following 5 dungeon titles, randomly select only one of them. Output only the title, no explanation, no numbering, no extra text: ${titles5.join("\n")}`, @@ -129,7 +129,7 @@ ${titles5.join("\n")}`, // --- Step 4: Flavor text --- const flavorRaw = await callOllama( `Write a single evocative paragraph describing the dungeon titled "${title}". -Do not include hooks, NPCs, treasure, or instructions. Output plain text only, one paragraph.`, +Do not include hooks, NPCs, treasure, or instructions. Output plain text only, one paragraph. Maximum 4 sentences.`, undefined, 5, "Step 4: Flavor" ); const flavor = flavorRaw; @@ -141,40 +141,23 @@ Do not include hooks, NPCs, treasure, or instructions. Output plain text only, o ${flavor} -Generate 3 adventure hooks (one sentence each) and 3 rumors (one sentence each). -Output numbered lists only, plain text. Maximum 120 characters per item. No explanations or extra text. -Format as: - -Hooks: -1. ... -2. ... -3. ... - -Rumors: -1. ... -2. ... -3. ...` -, +Generate 3 short adventure hooks or rumors (mix them naturally). +Output as a single numbered list, plain text only. +Maximum 2 sentences per item. No explanations or extra text.`, undefined, 5, "Step 5: Hooks & Rumors" ); - const [hooksSection, rumorsSection] = hooksRumorsRaw.split(/Rumors[:\n]/i); - const hooks = parseList(hooksSection.replace(/Hooks[:\n]*/i, ""), 120); - const rumors = parseList(rumorsSection || "", 120); - console.log("šŸ”¹ Hooks:", hooks); - console.log("šŸ”¹ Rumors:", rumors); + const hooksRumors = parseList(hooksRumorsRaw, 120); + console.log("šŸ”¹ Hooks & Rumors:", hooksRumors); // --- Step 6: Rooms & Encounters --- const roomsEncountersRaw = await callOllama( - `Using the flavor, hooks, and rumors: + `Using the flavor and these hooks/rumors: Flavor: ${flavor} -Hooks: -${hooks.join("\n")} - -Rumors: -${rumors.join("\n")} +Hooks & Rumors: +${hooksRumors.join("\n")} Generate 5 rooms (name + short description) and 3 encounters (name + details). Output two numbered lists, labeled "Rooms:" and "Encounters:". Plain text only. No extra explanation.`, @@ -197,11 +180,33 @@ Output numbered lists labeled "Treasure:" and "NPCs:". Plain text only, no extra undefined, 5, "Step 7: Treasure & NPCs" ); const [treasureSection, npcsSection] = treasureNpcsRaw.split(/NPCs[:\n]/i); - const treasure = parseList(treasureSection.replace(/Treasure[:\n]*/i, ""), 120); + const treasure = parseList(treasureSection.replace(/Treasures?[:\n]*/i, ""), 120); const npcs = parseObjects(npcsSection || "", "npcs", 120); console.log("šŸ”¹ Treasure:", treasure); console.log("šŸ”¹ NPCs:", npcs); + // --- Step 8: Plot Resolutions --- + const plotResolutionsRaw = await callOllama( + `Based on the following dungeon flavor and story hooks: + +Flavor: +${flavor} + +Hooks & Rumors: +${hooksRumors.join("\n")} + +Major NPCs / Encounters: +${[...npcs.map(n => n.name), ...encounters.map(e => e.name)].join(", ")} + +Suggest 3 possible, non-conflicting story climaxes or plot resolutions for adventurers exploring this dungeon. +These are prompts and ideas for brainstorming the dungeon's ending, not fixed outcomes. +Start each item with phrases like "The adventurers could..." or "The PCs might..." to emphasize their hypothetical nature. +Keep each item short (max 2 sentences). Output as a numbered list, plain text only.`, + undefined, 5, "Step 8: Plot Resolutions" + ); + const plotResolutions = parseList(plotResolutionsRaw, 180); + console.log("šŸ”¹ Plot Resolutions:", plotResolutions); + console.log("\nšŸŽ‰ Dungeon generation complete!"); - return { title, flavor, map: "map.png", hooks, rumors, rooms, encounters, treasure, npcs }; + return { title, flavor, map: "map.png", hooksRumors, rooms, encounters, treasure, npcs, plotResolutions }; } diff --git a/dungeonTemplate.js b/dungeonTemplate.js index 095365a..f2135e9 100644 --- a/dungeonTemplate.js +++ b/dungeonTemplate.js @@ -4,36 +4,31 @@ function pickRandom(arr) { export function dungeonTemplate(data) { const bodyFonts = [ - "'Libre Baskerville', serif", - "'Cardo', serif", + "'Lora', serif", "'Merriweather', serif", - "'Fraunces', serif", - "'Source Serif 4', serif", - "'Lora', serif" + "'Libre Baskerville', serif", + "'Source Serif 4', serif" ]; const headingFonts = [ "'Cinzel Decorative', cursive", "'MedievalSharp', cursive", "'Metamorphous', cursive", - "'Playfair Display', serif", - "'Alegreya Sans SC', sans-serif" + "'Playfair Display', serif" ]; const tableFonts = [ "'Alegreya Sans', sans-serif", "'Cabin', sans-serif", "'IBM Plex Sans', sans-serif", - "'Cormorant Garamond', serif", - "'Special Elite', monospace" + "'Cormorant Garamond', serif" ]; const quoteFonts = [ "'Walter Turncoat', cursive", "'Uncial Antiqua', serif", "'Beth Ellen', cursive", - "'Pinyon Script', cursive", - "'Dela Gothic One', sans-serif" + "'Pinyon Script', cursive" ]; const bodyFont = pickRandom(bodyFonts); @@ -47,62 +42,69 @@ export function dungeonTemplate(data) { ${data.title} - + @@ -112,18 +114,10 @@ export function dungeonTemplate(data) {
-

Map

-
Dungeon Map
+

Adventure Hooks & Rumors

+
    ${data.hooksRumors.map(item => `
  • ${item}
  • `).join("")}
-

Adventure Hooks

-
    ${data.hooks.map(h => `
  • ${h}
  • `).join("")}
- -

Rumors

-
    ${data.rumors.map(r => `
  • ${r}
  • `).join("")}
-
- -
-

Keyed Rooms

+

Locations

${data.rooms.map((room, i) => `

${i + 1}. ${room.name}

${room.description}

`).join("")}
@@ -135,12 +129,22 @@ export function dungeonTemplate(data) {

Treasure

+
+

NPCs

+ +

Plot Resolutions

+
+
+

Dungeon Map

+ Dungeon Map +
+ diff --git a/package.json b/package.json index cc60891..f612433 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "auto-dm", + "name": "scrollsmith", "version": "1.0.0", "main": "index.js", "type": "module",