Traditional Animation Exposure Sheet (X-Sheet) Creator

Animation X-Sheet Creator

X-Sheet Animator

Exposure Sheet Creator
🎬

Scene Metadata

Frame-by-Frame Timing

Enter the action for each frame. Dialogue and Sound will appear on the final sheet.

Frame
Action / Keyframe (A)
Dialogue (B)
Sound / Music (C)
Camera / Notes

X-Sheet Output

Click 'Refresh Sheet' or enter data to view the Exposure Sheet.

No frames entered. Use the builder tab to start charting the action.

'; return; } let tableHtml = ` `; frameData.forEach(row => { tableHtml += ` `; }); tableHtml += `
SCENE: ${metadata.scene} ANIMATOR: ${metadata.animator} FPS: ${metadata.fps}
# ACTION / DRAWING (A) DIALOGUE (B) SOUND / FX (C) CAMERA / NOTES
${row.frame} ${row.action} ${row.dialogue} ${row.sound} ${row.camera}
`; preview.innerHTML = tableHtml; } // Debounced render wrapper for input fields let xscRenderTimeout; const xscDebouncedRender = () => { clearTimeout(xscRenderTimeout); xscRenderTimeout = setTimeout(xscRenderSheet, 500); }; function xscLoadExample() { if(!confirm("Overwrite current data with an example walk cycle (24 frames)?")) return; document.getElementById('inp-scene').value = "S02 - Simple Walk Cycle"; document.getElementById('inp-animator').value = "B. Chuck"; const rowsContainer = document.getElementById('xsc-frame-rows'); rowsContainer.innerHTML = ''; xscTotalFrames = 0; const data = [ { frame: 1, action: "Key Pose: Contact (R foot forward)", dialogue: "", sound: "START: Theme Music Cue", camera: "Pan Right (Slow)" }, { frame: 2, action: "", dialogue: "", sound: "" }, { frame: 3, action: "Breakdown", dialogue: "", sound: "" }, { frame: 4, action: "", dialogue: "LINE 1", sound: "" }, { frame: 5, action: "Key Pose: Passing", dialogue: "", sound: "" }, { frame: 6, action: "", dialogue: "", sound: "" }, { frame: 7, action: "Breakdown", dialogue: "", sound: "" }, { frame: 8, action: "Key Pose: Down (Low point)", dialogue: "LINE 2", sound: "" }, { frame: 9, action: "", dialogue: "", sound: "" }, { frame: 10, action: "Inbetween", dialogue: "", sound: "" }, { frame: 11, action: "Breakdown", dialogue: "", sound: "" }, { frame: 12, action: "Key Pose: Contact (L foot forward)", dialogue: "LINE 3", sound: "Footstep FX" }, ]; data.forEach(d => xscAddFrameRow(d.frame, 1)); // Since the frames were added sequentially, we now update their content const inputs = document.querySelectorAll('.xsc-frame-row'); data.forEach((d, i) => { if(inputs[i]) { inputs[i].querySelector('.inp-action').value = d.action; inputs[i].querySelector('.inp-dialogue').value = d.dialogue; inputs[i].querySelector('.inp-sound').value = d.sound; inputs[i].querySelector('.inp-camera').value = d.camera; } }); xscRenderSheet(); xscSwitchTab('preview'); } /* --- PDF Generation --- */ async function xscGeneratePDF() { xscRenderSheet(); // Final render update const metadata = { scene: document.getElementById('inp-scene').value, animator: document.getElementById('inp-animator').value, fps: document.getElementById('inp-fps').value }; const frameData = xscGetFrameData(); if (frameData.length === 0) { alert("Please enter frame data before generating the PDF."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF('l', 'mm', 'a4'); // LANDSCAPE Orientation // Prepare table data const tableBody = frameData.map(row => [ row.frame, row.action, row.dialogue, row.sound, row.camera ]); doc.autoTable({ startY: 20, head: [ [ { content: `X-SHEET | SCENE: ${metadata.scene}`, colSpan: 3 }, { content: `ANIMATOR: ${metadata.animator}`, colSpan: 1 }, { content: `FPS: ${metadata.fps}`, colSpan: 1 } ], [ "FRAME #", "ACTION / DRAWING (A)", "DIALOGUE (B)", "SOUND / FX (C)", "CAMERA / NOTES" ] ], body: tableBody, theme: 'grid', headStyles: { fillColor: [0, 128, 128], textColor: 255, fontSize: 10, fontStyle: 'bold' }, styles: { fontSize: 8, cellPadding: 1 }, columnStyles: { 0: { cellWidth: 12, fontStyle: 'bold' }, // Frame # 1: { cellWidth: 50, overflow: 'linebreak' }, // Action 2: { cellWidth: 50, overflow: 'linebreak' }, // Dialogue 3: { cellWidth: 50, overflow: 'linebreak' }, // Sound 4: { cellWidth: 'auto', overflow: 'linebreak' } // Camera } }); doc.save(`X_Sheet_${metadata.scene.replace(/\s+/g, '_')}.pdf`); }
Scroll to Top