Animation Storyboard Template

Animation Storyboard Template

Visual and Timing Breakdown (Frames and Seconds)

Scene Duration: 00:00

Project Title

Scene: Scene 1.0 | Animator/Director: N/A

Frame Rate: 24 fps | Total Frames: 0


Project Definition

Panel Editor

Define the visual and audio content for each panel. Frame counts are crucial for timing.

No panels defined. Add panels in the editor.

"; return; } asbData.panels.forEach((panel, index) => { const duration = framesToTime(panel.frames, fps); const totalFrames = parseInt(panel.frames) || 0; const panelDiv = document.createElement('div'); panelDiv.className = 'asb-panel'; panelDiv.innerHTML = `
PANEL: ${index + 1} (${panel.shotId || 'N/A'}) DUR: ${duration} | FRAMES: ${totalFrames}
VISUAL (Sketch or Image Placeholder)
ACTION & STAGING

${panel.action || '---'}

CAMERA: ${panel.camera || 'Static'}

AUDIO / DIALOGUE

${panel.audio || '---'}

`; outputs.panelGrid.appendChild(panelDiv); }); } function renderPanelEditor() { outputs.panelEditorContainer.innerHTML = ""; asbData.panels.forEach((panel, index) => { const card = document.createElement('div'); card.className = 'asb-edit-panel'; card.innerHTML = `

Panel ${index + 1}

`; outputs.panelEditorContainer.appendChild(card); }); attachDynamicEditorListeners(); } // --- 5. EVENT LISTENERS & ACTIONS --- function attachListeners() { // Meta Inputs const metaInputs = Object.values(inputs).filter(i => !i.id.includes('panel-')); metaInputs.forEach(inp => inp.addEventListener('input', renderAll)); // Add Panel Button document.getElementById('btn-add-panel').addEventListener('click', addPanel); } function attachDynamicEditorListeners() { const updatePanelField = (e, field) => { const id = parseInt(e.target.dataset.id); const panel = asbData.panels.find(p => p.id === id); if (panel) { if (field === 'frames') panel[field] = parseInt(e.target.value) || 0; else panel[field] = e.target.value; renderAll(); } }; document.querySelectorAll('.panel-shot-id').forEach(inp => inp.addEventListener('input', (e) => updatePanelField(e, 'shotId'))); document.querySelectorAll('.panel-frames').forEach(inp => inp.addEventListener('input', (e) => updatePanelField(e, 'frames'))); document.querySelectorAll('.panel-action').forEach(inp => inp.addEventListener('input', (e) => updatePanelField(e, 'action'))); document.querySelectorAll('.panel-camera').forEach(inp => inp.addEventListener('input', (e) => updatePanelField(e, 'camera'))); document.querySelectorAll('.panel-audio').forEach(inp => inp.addEventListener('input', (e) => updatePanelField(e, 'audio'))); } // Dynamic Actions window.addPanel = function() { const nextShotId = asbData.panels.length > 0 ? (asbData.panels.length + 1) + 'A' : '1A'; asbData.panels.push({ id: Date.now(), shotId: nextShotId, frames: 48, action: "", camera: "MS", audio: "" }); renderAll(); // Scroll to the new panel in the editor setTimeout(() => outputs.panelEditorContainer.lastChild.scrollIntoView({ behavior: 'smooth' }), 100); }; window.removePanel = function(id) { if(confirm("Remove this panel?")) { asbData.panels = asbData.panels.filter(p => p.id !== id); renderAll(); } }; // --- 6. TAB NAVIGATION --- window.asbSwitchTab = function(tabId) { if (tabId === 'tab-panels') renderPanelEditor(); // Ensure editor is fresh document.querySelectorAll('.asb-tab-pane').forEach(p => p.classList.remove('active')); document.querySelectorAll('.asb-tab-btn').forEach(b => b.classList.remove('active')); document.getElementById(tabId).classList.add('active'); document.querySelector(`.asb-tab-btn[data-tab="${tabId}"]`).classList.add('active'); document.getElementById('animation-sb-tool').scrollIntoView({behavior: 'smooth'}); }; document.querySelectorAll('.asb-tab-btn').forEach(btn => { btn.addEventListener('click', function() { asbSwitchTab(this.dataset.tab); }); }); // --- 7. PDF EXPORT --- const btnDown = document.getElementById('asb-download-btn'); if(btnDown) { btnDown.addEventListener('click', function() { renderAll(); const element = document.getElementById('asb-render-area'); const filename = (inputs.projectTitle.value || 'Animation_SB').replace(/\s+/g,'_'); const opt = { margin: 0.3, filename: `${filename}_Storyboard_Scene_${inputs.sceneNum.value}.pdf`, image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, useCORS: true }, jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' } }; const origText = btnDown.innerText; btnDown.innerText = "Generating Storyboard..."; html2pdf().set(opt).from(element).save().then(() => { btnDown.innerText = origText; }); }); } // Start init(); });
Scroll to Top