Character Builder for Stories
Can be a number or description (e.g., "45", "Late 20s", "Ancient").
What is their main function in the plot?
Height, build, hair/eye color, notable features.
What do they usually wear?
List their positive traits.
What are their weaknesses or negative traits?
What one thing drives them above all else?
Give a brief history of their life before the story begins.
What single past event shaped them the most?
Review your complete character profile below. Go back to any tab to make edits.
Click "Generate/Refresh Summary" to see your character sheet here.
Key Event: ${escapeHTML(data.keyEvent)}
`; }; const downloadPDF = () => { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('Error: jsPDF library not loaded.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'mm', 'a4'); const data = getCharacterData(); const margin = 20; const pageWidth = doc.internal.pageSize.getWidth(); const usableWidth = pageWidth - (margin * 2); let yPos = 25; // Start position // Helper function to add a formatted section const addSection = (title, text) => { if (!text || text === 'Not provided') { text = '...'; // Placeholder for empty fields } if (yPos > 260) { // Check for page break doc.addPage(); yPos = 20; } doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(44, 62, 80); // Dark blue doc.text(title, margin, yPos); yPos += 8; doc.setFontSize(11); doc.setFont(undefined, 'normal'); doc.setTextColor(52, 73, 94); // Dark gray const splitText = doc.splitTextToSize(text, usableWidth); doc.text(splitText, margin, yPos); yPos += (splitText.length * 5) + 5; // 5mm per line + 5mm buffer }; // --- Build PDF Document --- doc.setFontSize(20); doc.setFont(undefined, 'bold'); doc.setTextColor(0, 123, 255); // Blue doc.text("Character Profile", pageWidth / 2, 15, { align: 'center' }); addSection("Name", data.name); addSection("Age", data.age); addSection("Role in Story", data.role); addSection("Physical Description", data.physical); addSection("Typical Attire", data.attire); addSection("Strengths / Virtues", data.strengths); addSection("Flaws / Vices", data.flaws); addSection("Primary Motivation", data.motivation); addSection("Backstory Summary", data.backstory); addSection("Key Life Event", data.keyEvent); doc.save('character-profile.pdf'); }; // --- Utility --- const escapeHTML = (str) => { if (typeof str !== 'string') return ''; return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); }; // --- Event Listeners --- // Tab Buttons tabButtons.forEach((btn, index) => { btn.addEventListener('click', () => showTab(index + 1)); }); // Next/Prev Navigation nextBtn.addEventListener('click', () => showTab(currentTab + 1)); prevBtn.addEventListener('click', () => showTab(currentTab - 1)); // Tab 5 Actions generateSummaryBtn.addEventListener('click', generateSummary); downloadPdfBtn.addEventListener('click', downloadPDF); // --- Initialization --- showTab(1); // Set initial state });