import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const WIKI_ROOT = path.resolve(__dirname, "../../wiki-content");
function ensureDir(dirPath: string) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
function writePage(relPath: string, title: string, type: string, tags: string[], body: string) {
// Always write to 'en' subdirectory to match Wiki.js structure
const fullPath = path.join(WIKI_ROOT, "en", relPath);
ensureDir(path.dirname(fullPath));
const content = `---
title: "${title}"
type: ${type}
tags: ${tags.join(", ")}
---
# ${title}
${body}
`;
fs.writeFileSync(fullPath, content);
console.log(`Created: ${relPath}`);
}
console.log("Generating Scaled Fantasy Content...");
const LOCATIONS = [
"Shadowed Valley", "Iron Citadel", "Whispering Woods", "Sunken Temple", "Crimson Peak",
"Mirror Lake", "Ancient Ruins of Zor", "Market of a Thousand Scents"
];
const FACTIONS = [
"The Iron Legion", "Circle of Mages", "Thieves' Guild", "The Silent Watchers", "Merchants' Consortium"
];
const ADJECTIVES = ["Dark", "Ancient", "Lost", "Forgotten", "Crystal", "Blood", "Shadow", "Light", "Eternal", "Broken"];
const NOUNS = ["Spire", "Keep", "Haven", "Rest", "Falls", "Gate", "Bridge", "Tower", "Sanctuary", "Void"];
// Generate 50 Procedural Locations
for (let i = 0; i < 50; i++) {
const name = `${ADJECTIVES[i % ADJECTIVES.length]} ${NOUNS[i % NOUNS.length]} ${i}`;
const faction = FACTIONS[i % FACTIONS.length];
writePage(
`locations/generated/loc-${i}.md`,
name,
"location",
["generated", "procedural", faction.toLowerCase().replace(/ /g, "-")],
`**${name}** is a notable landmark under the control of [${faction}](/en/lore/organizations/${faction.toLowerCase().replace(/ /g, "-")}).
## Description
Travelers often speak of the [Aether](/en/magic/aether-magic) disturbances found here. It is rumored that [The Shadow King](/en/characters/antagonists/shadow-king) once visited this place.
## Connecting Locations
- [Oakhaven](/en/locations/cities/oakhaven)
- [${ADJECTIVES[(i + 1) % ADJECTIVES.length]} ${NOUNS[(i + 1) % NOUNS.length]} ${(i + 1)}](/en/locations/generated/loc-${(i + 1) % 50})`
);
}
// Generate 50 Procedural Characters
const NAMES = ["Thorne", "Elara", "Garrick", "Lyra", "Malakor", "Seraphina", "Kaelen", "Vorath", "Isolde", "Dorian"];
const TITLES = ["the Brave", "the Cursed", "of the Watch", "Iron-Heart", "Shadow-Walker", "Light-Bringer"];
for (let i = 0; i < 50; i++) {
const name = `${NAMES[i % NAMES.length]} ${TITLES[i % TITLES.length]} ${i}`;
const locIdx = i; // simple mapping
const locationName = `${ADJECTIVES[i % ADJECTIVES.length]} ${NOUNS[i % NOUNS.length]} ${i}`;
writePage(
`characters/generated/char-${i}.md`,
name,
"character",
["npc", "generated"],
`**${name}** can often be found in [${locationName}](/en/locations/generated/loc-${i}).
## Role
They serve as a contact for the [Solar Guard](/en/lore/organizations/solar-guard) and have deep knowledge of [Magic](/en/magic/aether-magic).
## Quests
- **Retrieve the Artifact**: ${name} seeks a [Star-Steel Blade](/en/artifacts/star-steel-blade).`
);
}
// Generate 20 More Chapters
for (let i = 3; i <= 23; i++) {
const locName = `${ADJECTIVES[i % ADJECTIVES.length]} ${NOUNS[i % NOUNS.length]} ${i}`;
const charName = `${NAMES[i % NAMES.length]} ${TITLES[i % TITLES.length]} ${i}`;
writePage(
`novel/act-2/chapter-${i}.md`,
`Chapter ${i}: The Journey Continues`,
"chapter",
["act-2", "generated"],
`The party traveled to [${locName}](/en/locations/generated/loc-${i}).
[Kaelen](/en/characters/protagonists/kaelen) felt the weight of the [Mark of the Void](/en/magic/void-mark) grow heavier.
"We must press on," said [${charName}](/en/characters/generated/char-${i}).`
);
}
console.log("Scaled generation complete! (~120 files created)");