Restorative Practices in Schools Circle Script Generator

Restorative Practices Circle Script Generator

1. Circle Context
2. Core Prompts

Select the best prompt for each phase of your circle.

Click "Generate Script" to preview your circle facilitation guide.

Add New Prompt

Current Prompt Library

Phase Prompt Text Action

Please select at least one prompt in the Builder tab.

'; pdfDownloadBtn.disabled = true; return; } // --- 1. Header --- let html = `

${data.title}

Type: ${data.type} Circle | Participants: ${data.participants}

Follow the prompts below using the talking piece. Ensure all participants have a chance to speak without interruption.

`; // --- 2. Phases --- data.phases.forEach((phase, index) => { html += `

Phase ${index + 1}: ${phase.name}

Purpose: ${phase.context}
  1. Facilitator speaks first: "Welcome everyone. The purpose of this circle is to [State purpose using Title/Type]."
  2. Facilitator introduces the talking piece and ground rules.
  3. Core Prompt: ${phase.prompt}
`; }); reviewArea.innerHTML = html; pdfDownloadBtn.disabled = false; switchTab(1); // Switch to review tab } /** * PDF Generation Function * V.A.1, IX: MUST be fully functional and nicely formatted. */ function downloadPDF() { const data = getScriptData(); const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'pt', 'a4'); let currentY = 40; const margin = 40; const pageWidth = doc.internal.pageSize.width; const maxWidth = pageWidth - (margin * 2); const checkPageBreak = (spaceNeeded) => { if (currentY + spaceNeeded > doc.internal.pageSize.height - margin) { doc.addPage(); currentY = margin; } }; // Helper to add text and manage Y position const addText = (text, size = 11, style = 'normal', indent = 0, color = 0) => { doc.setFontSize(size); doc.setFont('Helvetica', style); doc.setTextColor(color); const lines = doc.splitTextToSize(text, maxWidth - indent); checkPageBreak(lines.length * (size * 0.8)); doc.text(lines, margin + indent, currentY); currentY += (lines.length * (size * 1.2)); // Line height multiplier doc.setTextColor(0); // Reset color }; // --- PDF Content --- // Title Block doc.setFontSize(22); doc.setFont('Helvetica', 'bold'); doc.setTextColor(0, 123, 255); // Primary color addText(data.title.toUpperCase(), 22, 'bold', 0, [0, 123, 255]); doc.setFontSize(14); addText(`Type: ${data.type} Circle | Participants: ${data.participants}`, 14, 'normal', 0, [108, 117, 125]); currentY += 15; // Introduction addText('Restorative Circle Facilitation Script', 12, 'bold'); addText('Follow the prompts below using the talking piece. Ensure all participants have a chance to speak without interruption.', 10, 'italic', 5); currentY += 10; // Phases data.phases.forEach((phase, index) => { checkPageBreak(50); // Ensure enough space for the whole phase block // Phase Header doc.setDrawColor(0, 123, 255); // Primary color border doc.setLineWidth(2); doc.line(margin, currentY, margin, currentY + 30); doc.setFontSize(15); doc.setFont('Helvetica', 'bold'); doc.setTextColor(0, 123, 255); // Primary color addText(`Phase ${index + 1}: ${phase.name}`, 15, 'bold', 10, [0, 123, 255]); // Purpose/Context addText(`Purpose: ${phase.context}`, 10, 'italic', 10, [108, 117, 125]); // Step 1 addText(`1. Facilitator speaks first: "Welcome everyone. The purpose of this circle is to [State purpose using Title/Type]."`, 10, 'normal', 10); // Step 2 addText('2. Facilitator introduces the talking piece and ground rules.', 10, 'normal', 10); // Core Prompt (Highlighted) doc.setFontSize(12); doc.setFont('Helvetica', 'bold'); doc.setTextColor(40, 167, 69); // Success color addText(`3. Core Prompt: ${phase.prompt}`, 12, 'bold', 10, [40, 167, 69]); currentY += 10; }); doc.save(`${data.title.replace(/\s/g, '_') || 'Restorative_Circle'}_Script.pdf`); } // --- Event Listeners --- generateBtn.addEventListener('click', generateScript); pdfDownloadBtn.addEventListener('click', downloadPDF); // --- Tab Navigation --- function switchTab(tabIndex) { tabs.forEach((tab, index) => { tab.classList.toggle('active', index === tabIndex); contents[index].classList.toggle('active', index === tabIndex); }); currentTab = tabIndex; updateNavButtons(); } function updateNavButtons() { prevBtn.disabled = currentTab === 0; nextBtn.disabled = currentTab === tabs.length - 1; } tabs.forEach((tab, index) => { tab.addEventListener('click', () => switchTab(index)); }); nextBtn.addEventListener('click', () => { if (currentTab < tabs.length - 1) switchTab(currentTab + 1); }); prevBtn.addEventListener('click', () => { if (currentTab > 0) switchTab(currentTab - 1); }); // --- Initial Setup --- populatePhaseSelects(); renderPromptLibrary(); updateNavButtons(); });
Scroll to Top