Scrapbooking Page Layout Idea

Scientific Poster Generator

Keep it short, clear, and impactful.

What is the problem, gap, or motivation? (Keep text minimal for a poster).

What did you do? Focus on the key, novel steps.

State the main quantitative findings (e.g., accuracy, significance, major trends).

Figures/Visuals Builder

Define the visuals and their captions for the results section.

Summarize findings and next research steps.

List 3-5 key citations.

Poster Content Preview (3-Column Layout)

Click "Next" or "Previous" to refresh this preview.

${escapeHTML(data.authors)}

[${escapeHTML(data.conference)} | Size: ${escapeHTML(data.size)}]

Background

${formatParagraphs(data.background)}

Methods

${formatParagraphs(data.methods)}

Results

${formatParagraphs(data.results)}
${figuresHTML}

Conclusion

${formatParagraphs(data.conclusion)}

References

${formatParagraphs(data.references)}

SCAN FOR QR CODE / CONTACT INFO

`; }; const downloadTxt = () => { const data = getPosterData(); let content = `--- SCIENTIFIC POSTER CONTENT DRAFT ---\n`; content += "========================================\n\n"; content += `TITLE: ${data.title.toUpperCase()}\n`; content += `AUTHORS: ${data.authors}\n`; content += `CONTEXT: ${data.conference} | Size: ${data.size}\n`; content += "========================================\n\n"; content += "1. BACKGROUND/INTRODUCTION\n"; content += "----------------------------------------\n"; content += data.background.split('\n').map(p => p.trim()).join('\n') + '\n\n'; content += "2. METHODS\n"; content += "----------------------------------------\n"; content += data.methods.split('\n').map(p => p.trim()).join('\n') + '\n\n'; content += "3. RESULTS SUMMARY\n"; content += "----------------------------------------\n"; content += data.results.split('\n').map(p => p.trim()).join('\n') + '\n\n'; content += "4. CONCLUSION & FUTURE WORK\n"; content += "----------------------------------------\n"; content += data.conclusion.split('\n').map(p => p.trim()).join('\n') + '\n\n'; content += "5. FIGURES & VISUALS\n"; content += "----------------------------------------\n"; data.figures.forEach((fig, index) => { content += `FIGURE ${index + 1} (${fig.size.toUpperCase()})\n`; content += ` Caption: ${fig.caption}\n`; content += ` Visual Placeholder: ${fig.url}\n\n`; }); content += "6. REFERENCES\n"; content += "----------------------------------------\n"; content += data.references.split('\n').map(p => p.trim()).join('\n') + '\n'; const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `${data.title.replace(/ /g, '_').substring(0, 30) || 'poster'}_content.txt`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(a.href); }; const downloadPDF = () => { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('Error: jsPDF library not loaded.'); return; } const { jsPDF } = window.jspdf; // Use A4 Landscape to represent the wide poster format const doc = new jsPDF('l', 'mm', 'a4'); const data = getPosterData(); const margin = 10; const pageWidth = doc.internal.pageSize.getWidth(); const columnWidth = (pageWidth - margin * 4) / 3; // 3 columns with 10mm margins const columnGap = 10; let yPos = 15; let currentColumn = 1; const addText = (text, size, style, xOffset, color = [52, 73, 94]) => { doc.setFontSize(size); doc.setFont(undefined, style); doc.setTextColor(color[0], color[1], color[2]); const lines = doc.splitTextToSize(text, columnWidth); if (yPos + (lines.length * 4) > 195) { // Check for page break (A4 height - 10mm bottom margin) doc.addPage('l'); yPos = 15; } doc.text(lines, margin + xOffset, yPos); yPos += (lines.length * 4) + 2; }; const addSection = (title, content) => { const xOffset = (currentColumn - 1) * (columnWidth + columnGap); // Add Section Title yPos += 3; doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(231, 76, 60); // Red doc.text(title.toUpperCase(), margin + xOffset, yPos); doc.setDrawColor(231, 76, 60); doc.setLineWidth(0.5); doc.line(margin + xOffset, yPos + 1, margin + xOffset + columnWidth, yPos + 1); yPos += 5; // Add Content addText(content, 10, 'normal', xOffset); }; const resetColumns = () => { currentColumn = 1; yPos = 50; // Reset Y below header }; // --- Build PDF Document --- // 1. Title Header Area (Across all columns) doc.setFontSize(22); doc.setFont(undefined, 'bold'); doc.setTextColor(44, 62, 80); doc.text(data.title.toUpperCase(), pageWidth / 2, yPos, { align: 'center' }); yPos += 8; doc.setFontSize(12); doc.setFont(undefined, 'normal'); doc.setTextColor(108, 117, 125); doc.text(data.authors, pageWidth / 2, yPos, { align: 'center' }); yPos += 5; doc.text(`[${data.conference} | Size: ${data.size}]`, pageWidth / 2, yPos, { align: 'center' }); yPos += 10; // Define starting Y for 3 columns let columnY = [yPos, yPos, yPos]; // --- Content Flow --- // Helper function to add content to the shortest column const addContentToShortest = (title, content, columnSpan = 1) => { // Find shortest column const minHeight = Math.min(...columnY); let shortestIndex = columnY.findIndex(h => h === minHeight); // Add Section Title const xOffset = shortestIndex * (columnWidth + columnGap); let currentY = columnY[shortestIndex]; if (currentY > 185) { // Start a new page if too close to the bottom doc.addPage('l'); columnY = [15, 15, 15]; // Reset all Ys shortestIndex = 0; currentY = 15; } currentY += 3; doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(231, 76, 60); // Red doc.text(title.toUpperCase(), margin + xOffset, currentY); doc.setDrawColor(231, 76, 60); doc.setLineWidth(0.5); doc.line(margin + xOffset, currentY + 1, margin + xOffset + columnWidth * columnSpan, currentY + 1); currentY += 5; // Add Content doc.setFontSize(10); doc.setFont(undefined, 'normal'); doc.setTextColor(52, 73, 94); let textToPrint = content.split('\n').filter(p => p.trim() !== '').join('\n'); const lines = doc.splitTextToSize(textToPrint, columnWidth * columnSpan); doc.text(lines, margin + xOffset, currentY); currentY += (lines.length * 4) + 5; // 4mm per line + buffer // Update the column height(s) if (columnSpan === 1) { columnY[shortestIndex] = currentY; } else if (columnSpan === 2) { columnY[shortestIndex] = currentY; columnY[shortestIndex + 1] = currentY; // Update the spanned column too } }; // Flow the content: addContentToShortest("Background", data.background); addContentToShortest("Methods", data.methods); // Results/Figures section is large, attempt to span two columns if (columnY[0] === columnY[1] && data.figures.length > 0) { // If first two columns are roughly equal, use a 2-column span let figureContent = data.results.split('\n').filter(p => p.trim() !== '').join('\n') + '\n\n'; data.figures.forEach((fig, index) => { figureContent += `\nFigure ${index + 1} (${fig.size.toUpperCase()}): ${fig.url}\nCaption: ${fig.caption}\n`; }); addContentToShortest("Results & Figures", figureContent, 2); } else { addContentToShortest("Results", data.results); addContentToShortest("Figures", data.figures.map((fig, index) => `Figure ${index+1} (${fig.size.toUpperCase()}): ${fig.caption} (${fig.url})`).join('\n')); } addContentToShortest("Conclusion", data.conclusion); addContentToShortest("References", data.references); // Footer const finalY = Math.max(...columnY); doc.setFontSize(8); doc.setTextColor(108, 117, 125); doc.text("Generated by Scientific Poster Generator | Content is for layout planning only.", pageWidth / 2, 200, { align: 'center' }); doc.save(`${data.title.replace(/ /g, '_').substring(0, 30) || 'scientific_poster'}.pdf`); }; // --- 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 3 Actions figureInputs.addBtn.addEventListener('click', addFigure); // Tab 4 Actions refreshBtn.addEventListener('click', generatePreview); downloadPdfBtn.addEventListener('click', downloadPDF); downloadTxtBtn.addEventListener('click', downloadTxt); // --- Initialization --- // Pre-populate with sample data inputs.title.value = "A Novel Approach to Deep-Sea Coral Taxonomy Using Machine Learning"; inputs.authors.value = "Jane Doe (MIT), John Smith (WHOI)"; inputs.conference.value = "Ocean Sciences Meeting, 2026"; inputs.background.value = "Deep-sea coral taxonomy relies heavily on visual inspection, leading to inconsistent species identification. Our study addresses the need for scalable, objective classification using computer vision techniques and a custom CNN model."; inputs.methods.value = "1. A dataset of 5,000 images was collected from five deep-sea ROV missions. 2. A custom Convolutional Neural Network (CNN) model was trained on a high-performance GPU cluster. 3. Model performance was validated using k-fold cross-validation against human expert labels."; inputs.results.value = "The CNN achieved a mean classification accuracy of 96.2% across 12 target species, exceeding the current human consensus rate of 88%. Training converged in 4.5 hours. See figures for confusion matrix and precision/recall data."; inputs.conclusion.value = "We successfully demonstrated a high-accuracy ML solution for coral taxonomy. This method is faster and more reliable than manual inspection. Future work will focus on integrating real-time ROV video processing."; inputs.references.value = "1. Smith et al., J. Marine Bio. (2020)\n2. Chen et al., Deep Sea Res. (2023)"; figureList.push({ id: figureIdCounter++, caption: "CNN architecture and training loss curve.", url: "Diagram: VGG-16 Architecture", size: "medium" }); figureList.push({ id: figureIdCounter++, caption: "Confusion matrix for the 12 target species.", url: "Table: Confusion Matrix PNG", size: "medium" }); figureList.push({ id: figureIdCounter++, caption: "Precision and Recall values vs. Depth.", url: "Bar Chart: Performance Metrics", size: "small" }); showTab(1); // Set initial state });
Scroll to Top