Adventure Story Idea Generator
Combine classic tropes to spark your next great tale.
Your Adventure Awaits...
Please make a selection from all dropdown menus to generate an idea.
`; resultsContainer.style.display = 'block'; pdfButtonContainer.style.display = 'none'; return; } const story = `In the heart of ${values.setting}, ${values.protagonist} is driven by a singular obsession: to find ${values.goal}. For years, it was nothing but a legend, a whisper in dusty tomes, but a recent discovery has put them on the path to truth.
However, they are not alone in their quest. The path is shadowed by ${values.antagonist}, who seek the prize for their own nefarious ends. Every step forward is a battle of wits and endurance, fraught with peril and unexpected alliances.
But the greatest danger may not be the pursuers or the treacherous environment. A startling revelation awaits: ${values.twist}. This changes everything, forcing our hero to question their mission, their allies, and the very nature of the treasure they seek.
`; storyOutput.innerHTML = story; resultsContainer.style.display = 'block'; pdfButtonContainer.style.display = 'block'; }; const downloadPDF = () => { try { const { jsPDF } = window.jspdf; const doc = new jsPDF(); const values = {}; const selectedOptions = {}; for (const key in selectors) { values[key] = selectors[key].value; selectedOptions[key] = selectors[key].options[selectors[key].selectedIndex].text; } const storyText = storyOutput.innerText; const pageHeight = doc.internal.pageSize.getHeight(); const pageWidth = doc.internal.pageSize.getWidth(); const margin = 20; let cursorY = margin; // --- PDF Header --- doc.setFont('helvetica', 'bold'); doc.setFontSize(20); doc.setTextColor(51, 65, 85); // Slate-700 doc.text('ADVENTURE DOSSIER', pageWidth / 2, cursorY, { align: 'center' }); cursorY += 8; doc.setFontSize(10); doc.setTextColor(150); doc.text('CLASSIFIED: FOR YOUR EYES ONLY', pageWidth / 2, cursorY, { align: 'center' }); cursorY += 12; doc.setDrawColor(161, 98, 7); // Yellow-700 doc.setLineWidth(0.5); doc.line(margin, cursorY, pageWidth - margin, cursorY); cursorY += 12; // --- Key Elements Table --- doc.setFontSize(14); doc.setFont('helvetica', 'bold'); doc.text('Mission Parameters:', margin, cursorY); cursorY += 5; const tableBody = [ ['PROTAGONIST:', selectedOptions.protagonist], ['OBJECTIVE:', selectedOptions.goal], ['LOCATION:', selectedOptions.setting], ['HOSTILES:', selectedOptions.antagonist], ['INTEL BRIEF:', selectedOptions.twist] ]; doc.autoTable({ startY: cursorY, head: [], body: tableBody, theme: 'striped', styles: { fontSize: 10, cellPadding: 3,}, headStyles: { fillColor: [71, 85, 105] }, // Slate-600 columnStyles: { 0: { fontStyle: 'bold', cellWidth: 40, fillColor: '#f8fafc' } } }); cursorY = doc.previousAutoTable.finalY + 15; // --- Narrative Synopsis --- doc.setFontSize(14); doc.setFont('helvetica', 'bold'); doc.text('Narrative Synopsis:', margin, cursorY); cursorY += 8; doc.setFont('helvetica', 'normal'); doc.setFontSize(11); doc.setTextColor(30, 41, 59); // Slate-800 const textLines = doc.splitTextToSize(storyText, pageWidth - margin * 2); doc.text(textLines, margin, cursorY); // --- 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} | Dossier Generated: ${new Date().toLocaleDateString()}`; doc.text(footerText, pageWidth / 2, pageHeight - 10, { align: 'center' }); } doc.save('Adventure_Story_Idea.pdf'); } catch (error) { console.error("Failed to generate PDF:", error); 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 generateButton.addEventListener('click', generateIdea); downloadPdfButton.addEventListener('click', downloadPDF); });