Screenplay Outline Generator

Screenplay Outline Generator

Screenplay Outline Generator

Structure your story beats across the Three-Act Narrative Model.

Enter each major scene or sequence, categorize it by **Act**, and provide a summary of the action.

Story Beats

Beat # Act Scene / Sequence Name Summary of Event / Action Action

Review the final chronological plot outline. Use the filters to focus on a specific Act.

${beat.act.toUpperCase()}

${beat.order}. ${beat.scene}

${beat.summary}

`; outlineList.appendChild(cardDiv); }); } // --- Tab Switching --- function sog_showTab(targetId, element) { tabButtons.forEach(btn => btn.classList.remove('sog-active')); document.querySelectorAll('.sog-tab-content').forEach(content => content.classList.remove('active')); if (element) { element.classList.add('sog-active'); } document.getElementById(targetId).classList.add('active'); if (targetId === 'review') { sog_renderReview(document.getElementById('act-filter').value); } } window.sog_showTab = sog_showTab; // --- PDF Export --- function sog_downloadPDF() { sog_collectBeatData(); const filterAct = document.getElementById('act-filter').value; if (typeof jspdf === 'undefined' || typeof jspdf.plugin.autotable === 'undefined') { alert('Error: PDF library not fully loaded for export.'); return; } const filteredBeats = filterAct === 'all' ? SOG_STATE.beats : SOG_STATE.beats.filter(c => c.act === filterAct); if (filteredBeats.length === 0) { alert('No beats match the current filter selection for export.'); return; } const { jsPDF } = jspdf; const doc = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); doc.setFont('sans-serif', 'normal'); const margin = 40; const pageWidth = doc.internal.pageSize.getWidth(); let yPos = margin; // --- Header --- doc.setFontSize(20); doc.setFont('sans-serif', 'bold'); doc.setTextColor('#1f2937'); // Gray-800 doc.text(`Screenplay Plot Outline (${filterAct === 'all' ? 'All Acts' : filterAct})`, pageWidth / 2, yPos, { align: 'center' }); yPos += 30; // --- Outline Table --- doc.setFontSize(10); const tableHeaders = ['#', 'Act', 'Scene/Sequence', 'Summary of Event']; const tableBody = filteredBeats.map((beat) => [ beat.order.toString(), beat.act, beat.scene, beat.summary ]); doc.autoTable({ head: [tableHeaders], body: tableBody, startY: yPos, theme: 'grid', styles: { fontSize: 9, cellPadding: 6, overflow: 'linebreak' }, headStyles: { fillColor: [31, 41, 55], textColor: 255, fontStyle: 'bold' }, // Gray-800 alternateRowStyles: { fillColor: [245, 245, 245] }, columnStyles: { 0: { cellWidth: 20, halign: 'center' }, 3: { cellWidth: 280 } // Summary gets space }, didDrawPage: function(data) { yPos = data.cursor.y; } }); doc.save(`Screenplay_Outline_${filterAct.replace(/\s/g, '_')}.pdf`); } // --- Initialization --- document.addEventListener('DOMContentLoaded', () => { // 1. Assign DOM elements (needed inside DOMContentLoaded scope) const actFilter = document.getElementById('act-filter'); // 2. Attach listeners document.getElementById('sog-add-beat-btn').addEventListener('click', sog_addBeat); document.getElementById('matrix-next-btn').addEventListener('click', () => sog_showTab('review', document.querySelector('.sog-tab-btn[data-tab="review"]'))); document.getElementById('sog-download-pdf').addEventListener('click', sog_downloadPDF); tabButtons.forEach(btn => { btn.addEventListener('click', (e) => sog_showTab(e.target.dataset.tab, e.target)); }); // Filter listener if(actFilter) actFilter.addEventListener('change', () => sog_renderReview(actFilter.value)); // 3. Initial population sog_renderMatrixTable(); });
Scroll to Top