Hero’s Journey Story Generator
Craft a timeless narrative using the 12-stage monomyth framework.
Part I: The Beginning
Part II: The Call to Adventure
Part III: Entering the New World
Part IV: The Ordeal & Reward
Part V: The Journey Home
Your Completed Story Outline
Your story outline will appear here once you fill out the previous steps and click "Generate Story".
An error occurred. A form field is missing from the page.
'; showTab(tabs.length - 1); return; } if (!storyData['hero-name']) { resultsContainer.innerHTML = 'Please provide a name for your hero before generating the story.
'; showTab(tabs.length - 1); return; } let htmlOutput = '';
for(const id in stageTitles) {
if(storyData[id]){
htmlOutput += `
`;
}
}
htmlOutput += '
';
resultsContainer.innerHTML = htmlOutput;
pdfButtonContainer.style.display = 'block';
showTab(tabs.length - 1);
};
const downloadPDF = () => {
try {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const storyData = {};
stageIds.forEach(id => storyData[id] = document.getElementById(id)?.value || 'N/A');
const heroName = storyData['hero-name'] || 'Untitled Story';
const pageHeight = doc.internal.pageSize.getHeight();
const pageWidth = doc.internal.pageSize.getWidth();
const margin = 18;
let cursorY = margin;
// --- PDF Header ---
doc.setFont('times', 'bold');
doc.setFontSize(26);
doc.setTextColor(45, 22, 82);
doc.text("The Hero's Journey", pageWidth / 2, cursorY, { align: 'center' });
cursorY += 10;
doc.setFont('times', 'italic');
doc.setFontSize(16);
doc.setTextColor(100, 100, 100);
doc.text(`A Story Outline for ${heroName}`, pageWidth / 2, cursorY, { align: 'center' });
cursorY += 15;
doc.setDrawColor(200, 200, 200);
doc.line(margin, cursorY, pageWidth - margin, cursorY);
cursorY += 12;
// --- Helper function for story sections ---
const addStorySection = (title, content) => {
const contentLines = doc.splitTextToSize(content, pageWidth - margin * 2);
const sectionHeight = 8 + (contentLines.length * 5); // Title height + text height
if (cursorY + sectionHeight > pageHeight - margin) {
doc.addPage();
cursorY = margin;
}
doc.setFontSize(14);
doc.setFont('times', 'bold');
doc.setTextColor(0, 0, 0);
doc.text(title, margin, cursorY);
cursorY += 7;
doc.setFont('times', 'normal');
doc.setFontSize(11);
doc.setTextColor(55, 65, 81);
doc.text(contentLines, margin, cursorY);
cursorY += (contentLines.length * 5) + 10;
};
// --- Build PDF Sections ---
for(const id in stageTitles) {
if(id !== 'hero-name' && storyData[id] && storyData[id] !== 'N/A') {
addStorySection(stageTitles[id], storyData[id]);
}
}
// --- Footer ---
const pageCount = doc.internal.getNumberOfPages();
for (let i = 1; i <= pageCount; i++) {
doc.setPage(i);
doc.setFontSize(9);
doc.setTextColor(150);
const footerText = `Page ${i} of ${pageCount} | ${heroName}`;
doc.text(footerText, pageWidth / 2, pageHeight - 10, { align: 'center' });
}
doc.save(`${heroName.replace(/\s+/g, '_')}_Heros_Journey.pdf`);
} catch (error) {
console.error("Failed to generate PDF:", error);
const pdfButtonContainer = document.getElementById('pdf-button-container');
if (pdfButtonContainer && !pdfButtonContainer.querySelector('.error-msg')) {
const errorMsg = document.createElement('p');
errorMsg.textContent = 'Sorry, an error occurred while creating the PDF.';
errorMsg.className = 'text-red-500 text-sm mt-2 error-msg';
pdfButtonContainer.appendChild(errorMsg);
}
}
};
// Event Listeners
prevButton.addEventListener('click', () => navigate(-1));
nextButton.addEventListener('click', () => navigate(1));
generateButton.addEventListener('click', generateStory);
downloadPdfButton.addEventListener('click', downloadPDF);
// Initial setup
showTab(0);
});
${stageTitles[id]}
${storyData[id]}
