Funeral Eulogy Generator
A guided tool to help you craft a heartfelt tribute.
This is the generated eulogy based on your inputs. Please review it below. You can go back to previous tabs to make edits.
We are gathered here today to celebrate the life of ${name}. ${relationship ? `As ${name}'s ${relationship}, I` : 'I'} wanted to share a few words about what a remarkable person they were.
`; } if (firstMemory) eulogyText += `One of my most cherished memories of ${name} is when ${firstMemory.replace(/\n/g, '
')}
I think we can all agree, ${name} had a wonderful sense of humor. I'll never forget the time ${funnyStory.replace(/\n/g, '
')}
When I think of ${name}, the words that come to mind are: ${qualities}. They truly embodied these qualities every single day.
`; if (passion) eulogyText += `They had such a deep passion for ${passion.replace(/\n/g, '
')}
The impact ${name} had on the people around them is immeasurable. ${impact.replace(/\n/g, '
')}
${closing.replace(/\n/g, '
')}
Thank you. ${name}, you will be deeply missed, but never forgotten.
`; } eulogyOutputDiv.innerHTML = eulogyText; currentTab = tabs.length - 1; showTab(currentTab); } /** * [REVISED] Generates and downloads a well-formatted, text-based PDF of the eulogy. * This version uses jsPDF's native text functions for a clean layout and small file size. */ function downloadPDF() { const name = document.getElementById('deceasedName').value.trim() || "[Deceased's Name]"; const relationship = document.getElementById('yourRelationship').value.trim(); const opening = document.getElementById('openingStatement').value.trim(); const firstMemory = document.getElementById('firstMemory').value.trim(); const funnyStory = document.getElementById('funnyStory').value.trim(); const qualities = document.getElementById('keyQualities').value.trim(); const passion = document.getElementById('passion').value.trim(); const impact = document.getElementById('impact').value.trim(); const closing = document.getElementById('closingMessage').value.trim(); const filename = `Eulogy for ${name}.pdf`; const { jsPDF } = window.jspdf; const doc = new jsPDF({ unit: 'pt', format: 'a4' }); const pageHeight = doc.internal.pageSize.height; const pageWidth = doc.internal.pageSize.width; const margin = 50; const contentWidth = pageWidth - margin * 2; let cursorY = margin; let pageNumber = 1; // Helper function to add text and manage page breaks const addText = (text, options) => { const { size = 11, style = 'normal', spaceAfter = 12, isHeading = false, align = 'left' } = options; doc.setFont('times', style); doc.setFontSize(size); const lines = doc.splitTextToSize(text, contentWidth); // Check if there's enough space for the whole block, otherwise start a new page const blockHeight = lines.length * (size * 1.15) + spaceAfter; if (cursorY + blockHeight > pageHeight - margin) { addFooter(); doc.addPage(); pageNumber++; cursorY = margin; addHeader(); } // For headings, add a bit more space before if(isHeading) { cursorY += 8; } // Determine the correct X position based on text alignment let xPos = margin; // Default for left alignment if (align === 'center') { xPos = pageWidth / 2; } else if (align === 'right') { xPos = pageWidth - margin; } doc.text(lines, xPos, cursorY, { align: align }); cursorY += lines.length * (size * 1.15) + spaceAfter; }; const addHeader = () => { doc.setFont('times', 'italic'); doc.setFontSize(9); doc.setTextColor(150); doc.text(`A Tribute to ${name}`, margin, margin / 2); doc.setTextColor(0); }; const addFooter = () => { doc.setFont('times', 'italic'); doc.setFontSize(9); doc.setTextColor(150); doc.text(`Page ${pageNumber}`, pageWidth - margin, pageHeight - margin / 2, {align: 'right'}); doc.setTextColor(0); } // --- Start Building PDF --- addHeader(); // Main Title addText('In Loving Memory of', { size: 24, style: 'bold', align: 'center', spaceAfter: 15 }); addText(name, { size: 20, style: 'italic', align: 'center', spaceAfter: 40 }); // Decorative Line doc.setDrawColor(180, 180, 180); doc.line(margin, cursorY, pageWidth - margin, cursorY); cursorY += 30; // Content Sections const introText = opening || `We are gathered here today to celebrate the life of ${name}. ${relationship ? `As ${name}'s ${relationship}, I` : 'I'} wanted to share a few words about what a remarkable person they were.`; addText('Introduction', { size: 14, style: 'bold', isHeading: true }); addText(introText, {}); if (firstMemory || funnyStory) { addText('Cherished Memories', { size: 14, style: 'bold', isHeading: true }); if (firstMemory) addText(firstMemory, {}); if (funnyStory) addText(funnyStory, {}); } if (qualities || passion) { addText('Their Unique Spirit', { size: 14, style: 'bold', isHeading: true }); if (qualities) addText(`Some of the words that best describe them are: ${qualities}.`, {}); if (passion) addText(passion, {}); } if (impact) { addText('A Lasting Legacy', { size: 14, style: 'bold', isHeading: true }); addText(impact, {}); } const closingText = closing || `Thank you. ${name}, you will be deeply missed, but never forgotten.`; addText('A Final Farewell', { size: 14, style: 'bold', isHeading: true }); addText(closingText, {}); addFooter(); doc.save(filename); } // --- Event Handling --- nextButton.addEventListener('click', () => { if (currentTab < tabs.length - 2) { currentTab++; showTab(currentTab); } }); prevButton.addEventListener('click', () => { if (currentTab > 0) { currentTab--; showTab(currentTab); } }); generateButton.addEventListener('click', generateEulogy); downloadPdfButton.addEventListener('click', downloadPDF); tabs.forEach(tab => { tab.addEventListener('click', () => { const tabIndex = parseInt(tab.dataset.tab, 10); if (tabIndex === tabs.length - 1 && eulogyOutputDiv.innerHTML.trim() === '') { generateEulogy(); } else { currentTab = tabIndex; showTab(currentTab); } }); }); // --- Initialization --- showTab(0); });