AI Story Script Generator — Write & Edit Narrated Stories

🎭 AI Tools # Tool 74

AI Story Script Generator

Generate a 4-act narrated script from your own instruction, then redirect any single section with your own idea and aim — never the whole script. Keeps a Story Bible for character/setting consistency, splits into sentence-safe editable parts, keeps a 3-version Undo history with Old vs New compare, and flags unsafe wording. Bring your own key (Gemini, OpenAI or Claude).

AI Story Script Generator

AI Story Script Generator

v1.2 AI-Powered / Needs Internet

Generate a 4-act narrated story from your own instruction (MD), edit and redirect any act, convert to natural spoken Sinhala, and export a clean script.

Import an Existing Story (optional)

Already have a script? Paste or upload it and split it into editable acts instead of generating from scratch.

New Story Premise

Spoken Sinhala Converter

Convert all generated acts from formal written language (ලිඛිත භාෂාව) to natural spoken language (ස්වාභාවික කතා කරන භාෂාව) suitable for YouTube storytelling. This will replace the text in all acts.

Continuity Checker

SEO Data (optional)

Vocabulary List (optional)

Export

Story Library

AI Provider

Instruction (MD)

📥 Download Sample Instruction (.md)

Using built-in generic instruction.

"; var blob = new Blob(['\ufeff', html], { type: 'application/msword' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = title.replace(/\s+/g, '-') + '.doc'; document.body.appendChild(a); a.click(); setTimeout(function() { document.body.removeChild(a); URL.revokeObjectURL(url); }, 200); }// --- NEW: Export as PDF (via Print window) --- function exportPDF() { var p = getActive(); if (!p) return; var printWindow = window.open('', '_blank'); if(!printWindow) { showToast('Popup blocked. Please allow popups to print/save PDF.', 'error'); return; } var html = "" + p.name + ""; html += ""; html += "

" + p.name + "

"; for (var i = 0; i < p.acts.length; i++) { if (p.acts[i].text) { html += "

" + p.acts[i].label + "

"; var paragraphs = p.acts[i].text.split('\n'); for (var j = 0; j < paragraphs.length; j++) { if(paragraphs[j].trim()) html += "

" + paragraphs[j].trim() + "

"; } } } html += ""; printWindow.document.write(html); printWindow.document.close(); printWindow.focus(); // Slight delay to allow CSS/fonts to render before print dialog setTimeout(function(){ printWindow.print(); // Option to auto-close window after print: printWindow.close(); }, 500); }function splitIntoActs(text, parts) { var words = (text || '').replace(/·\s+|\s+$/g, '').split(/\s+/); var total = words.length; var perPart = Math.max(1, Math.ceil(total / parts)); var acts = []; var i, chunk; for (i = 0; i < parts; i++) { chunk = words.slice(i * perPart, (i + 1) * perPart).join(' '); if (chunk) { acts.push(chunk); } } return acts; }function doImportSplit() { var text = $('sg-import-text').value; var fileInput = $('sg-import-file'); var partsCount = parseInt($('sg-import-parts').value, 10) || 4;function finish(finalText) { var chunks = splitIntoActs(finalText, partsCount); var p = newProjectObj('Imported Story', ''); p.acts = []; var i; for (i = 0; i < chunks.length; i++) { p.acts.push({ label: 'Act ' + (i + 1), text: chunks[i], aim: '', idea: '', history: [] }); } state.library.push(p); state.activeId = p.id; saveLibrary(); renderAll(); showToast('Story imported and split into ' + chunks.length + ' acts.', 'success'); }if (fileInput && fileInput.files && fileInput.files.length) { var reader = new FileReader(); reader.onload = function (e) { finish(e.target.result); }; reader.readAsText(fileInput.files[0]); } else if (text && text.replace(/·\s+|\s+$/g, '')) { finish(text); } else { showToast('Paste text or choose a file first.', 'error'); } }function loadPremiseFields() { var p = getActive(); if (!p) { return; } $('sg-premise').value = p.premise; $('sg-bible-chars').value = p.bible.characters; $('sg-bible-village').value = p.bible.village; $('sg-bible-era').value = p.bible.era; $('sg-bible-rule').value = p.bible.rule; }function bindPremiseFields() { var map = [ ['sg-premise', 'premise'], ['sg-bible-chars', 'characters'], ['sg-bible-village', 'village'], ['sg-bible-era', 'era'], ['sg-bible-rule', 'rule'] ]; var i; for (i = 0; i < map.length; i++) { (function (fieldId, key) { $(fieldId).addEventListener('change', function () { var p = getActive(); if (!p) { return; } if (key === 'premise') { p.premise = $(fieldId).value; } else { p.bible[key] = $(fieldId).value; } saveLibrary(); }); })(map[i][0], map[i][1]); } }function renderAll() { renderLibrarySelect(); loadPremiseFields(); renderActs(); renderParts(); var p = getActive(); $('sg-seo-output').style.display = p && p.seoText ? 'block' : 'none'; if (p && p.seoText) { $('sg-seo-output').textContent = p.seoText; } $('sg-vocab-output').style.display = p && p.vocabText ? 'block' : 'none'; if (p && p.vocabText) { $('sg-vocab-output').textContent = p.vocabText; } }function loadSample() { var p = getActive(); if (!p) { return; } p.premise = 'A young woman waiting by a well every evening for a husband who never returns from the tea estate.'; p.bible.characters = 'Somawathi, Podi Mahattaya'; p.bible.village = 'a small hill-country village'; p.bible.era = '1940s'; p.bible.rule = 'the well answers only after dark, and only once'; saveLibrary(); loadPremiseFields(); showToast('Sample premise loaded.', 'success'); }function attachEvents() { $('sg-load-sample').addEventListener('click', loadSample); $('sg-tab-story-btn').addEventListener('click', function () { showTab('story'); }); $('sg-tab-parts-btn').addEventListener('click', function () { showTab('parts'); }); $('sg-parts-split').addEventListener('click', doSplitParts); $('sg-parts-merge').addEventListener('click', mergePartsBack); $('sg-fullwidth').addEventListener('click', toggleFullWidth); $('sg-clear-all').addEventListener('click', function () { var p = getActive(); if (!p) { return; } var idx = state.library.indexOf(p); state.library[idx] = newProjectObj(p.name, ''); saveLibrary(); renderAll(); showToast('Project cleared.', 'success'); });$('sg-import-split').addEventListener('click', doImportSplit); $('sg-start-story').addEventListener('click', function () { generateAct(0); }); // NEW EVENT LISTENERS $('sg-convert-spoken').addEventListener('click', convertToSpoken); $('sg-export-word').addEventListener('click', exportWord); $('sg-export-pdf').addEventListener('click', exportPDF);$('sg-check-continuity').addEventListener('click', checkContinuity); $('sg-gen-seo').addEventListener('click', generateSEO); $('sg-gen-vocab').addEventListener('click', generateVocab); $('sg-export-full').addEventListener('click', exportFull); $('sg-export-clean').addEventListener('click', exportClean);$('sg-lib-select').addEventListener('change', function () { state.activeId = $('sg-lib-select').value; saveLibrary(); renderAll(); }); $('sg-lib-new').addEventListener('click', function () { var p = newProjectObj('New Story ' + (state.library.length + 1), ''); state.library.push(p); state.activeId = p.id; saveLibrary(); renderAll(); showToast('New story created.', 'success'); }); $('sg-lib-rename').addEventListener('click', function () { var p = getActive(); if (!p) { return; } $('sg-rename-input').value = p.name; $('sg-rename-row').style.display = 'block'; }); $('sg-rename-cancel').addEventListener('click', function () { $('sg-rename-row').style.display = 'none'; }); $('sg-rename-save').addEventListener('click', function () { var p = getActive(); if (!p) { return; } var val = $('sg-rename-input').value; if (val && val.replace(/·\s+|\s+$/g, '')) { p.name = val; saveLibrary(); renderAll(); showToast('Story renamed.', 'success'); } $('sg-rename-row').style.display = 'none'; }); $('sg-lib-delete').addEventListener('click', function () { if (state.library.length <= 1) { showToast('At least one story must remain.', 'error'); return; } var p = getActive(); var idx = state.library.indexOf(p); state.library.splice(idx, 1); state.activeId = state.library[0].id; saveLibrary(); renderAll(); showToast('Story deleted.', 'success'); });$('sg-provider').addEventListener('change', function () { var provider = $('sg-provider').value; $('sg-model').value = DEFAULT_MODELS[provider]; var keys = apiKeys(); $('sg-apikey').value = keys[provider] || ''; }); $('sg-apikey').addEventListener('change', function () { saveApiKey($('sg-provider').value, $('sg-apikey').value); });$('sg-md-fetch').addEventListener('click', function () { var url = $('sg-md-url').value; if (!url) { showToast('Enter a URL first.', 'error'); return; } fetch(url).then(function (r) { return r.text(); }).then(function (txt) { state.mdText = txt; state.mdSource = 'url'; $('sg-md-paste').value = txt; // UPDATED try { window.localStorage.setItem(LS.md, JSON.stringify({ source: 'url', text: txt, url: url })); } catch (e) {} updateMdStatus(); showToast('Instruction loaded from URL.', 'success'); }).catch(function () { showToast('Could not fetch that URL.', 'error'); }); }); $('sg-md-save').addEventListener('click', function () { var txt = $('sg-md-paste').value; if (!txt || !txt.replace(/·\s+|\s+$/g, '')) { showToast('Paste an instruction first.', 'error'); return; } state.mdText = txt; state.mdSource = 'paste'; try { window.localStorage.setItem(LS.md, JSON.stringify({ source: 'paste', text: txt })); } catch (e) {} updateMdStatus(); showToast('Instruction saved.', 'success'); }); }function updateMdStatus() { var status = $('sg-md-status'); if (state.mdSource === 'url') { status.textContent = 'Using instruction loaded from URL.'; } else if (state.mdSource === 'paste') { status.textContent = 'Using your pasted instruction.'; } else { status.textContent = 'Using built-in generic instruction (paste your own for full control).'; } }function toggleFullWidth() { var w = $('sict-storygen-wrap'); if (!w) { return; } var on = w.className.indexOf('sg-full') === -1; w.className = on ? 'sg-full' : ''; if (document.body) { if (on) { document.body.className += ' sg-locked'; } else { document.body.className = document.body.className.replace(/\s*sg-locked/g, ''); } } var btn = $('sg-fullwidth'); if (btn) { btn.textContent = on ? 'Exit Full Width' : 'Full Width'; } }function loadMdFromStorage() { var raw; try { raw = window.localStorage.getItem(LS.md); } catch (e) { raw = null; } if (raw) { try { var obj = JSON.parse(raw); if (obj && obj.text) { state.mdText = obj.text; state.mdSource = obj.source || 'paste'; $('sg-md-paste').value = obj.text; // UPDATED if (obj.url) { $('sg-md-url').value = obj.url; } updateMdStatus(); return; } } catch (e) {} } // Automatically load default instruction from the requested URL var defaultUrl = 'https://schoolict.net/sampledata/holman-katha-story-writer-TOOL-v1.0.md'; $('sg-md-url').value = defaultUrl; $('sg-md-status').textContent = 'Loading default instruction...'; fetch(defaultUrl).then(function (r) { return r.text(); }).then(function (txt) { state.mdText = txt; state.mdSource = 'url'; $('sg-md-paste').value = txt; // UPDATED updateMdStatus(); }).catch(function () { updateMdStatus(); }); }function init() { loadLibrary(); var provider = 'gemini'; $('sg-provider').value = provider; $('sg-model').value = DEFAULT_MODELS[provider]; var keys = apiKeys(); $('sg-apikey').value = keys[provider] || ''; loadMdFromStorage(); bindPremiseFields(); attachEvents(); renderAll(); }function runInit() { if (!window.sictStoryGenApp.initialized && document.getElementById('sict-storygen-wrap')) { window.sictStoryGenApp.initialized = true; window.sictStoryGenApp.init(); } }window.sictStoryGenApp = { initialized: false, init: init };runInit(); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', runInit); } window.addEventListener('load', function () { setTimeout(runInit, 50); }); if (!window.sictStoryGenApp.initialized && typeof MutationObserver !== 'undefined') { var sgObs = new MutationObserver(function () { if (document.getElementById('sict-storygen-wrap')) { sgObs.disconnect(); runInit(); } }); sgObs.observe(document.body || document.documentElement, { childList: true, subtree: true }); setTimeout(function () { sgObs.disconnect(); }, 10000); } })();

🟢 Your own instruction, not a fixed template

Paste any writing instruction into the Instruction (MD) box — tone, structure, language rules, whatever you want — and every act follows it, not a hardcoded script style.

🔵 Redirect any section, not the whole script

Pick a section, choose an aim like “increase fear” or “speed up the pacing”, add your own idea, and only that section is rewritten — the rest of the story stays untouched.

🟣 Undo without losing your edit

Every regeneration keeps your last versions on hand. Compare the old and new text side by side and choose which one to keep before anything is overwritten.

  1. Set your premise and bible. Fill in the Story Premise, Characters, Setting and Rule fields, then press Start New Story (Act 1) — or paste/upload an existing script instead.
  2. Split into working sections. Switch to the Parts (mini sections) tab and press Split Story Into Parts to break the story into small, sentence-safe chunks you can edit one at a time.
  3. Redirect a section. Open any part, choose an Aim, type your idea, and press Regenerate With This Direction — then compare and keep the version you prefer.
  4. Export what you need. Press Download Clean Narration (.txt) for a voiceover-ready file, or Download Full Copy (.md) to keep the markers, bible, SEO and vocabulary together.

🔴 Who actually reaches for this AI story generator

A few real situations this tool is built for:

  • 🔵A solo YouTube narrator who has a premise but not four acts of finished script, and wants a full draft to edit rather than a blank page.
  • 🟠A writer who already has a script from somewhere else and just wants to tighten one weak act without retyping the whole thing.
  • 🟣A teacher building a short audio drama for a class project, who needs the story split into small, gradable sections.

🟡 What “redirect a section” actually does

Say Act 2 of a horror story feels rushed. You open its card, choose the Aim Add more detail / description, type the idea “spend more time on the sound of the well at night”, and press Regenerate. The tool sends the model your premise, your story bible, the surrounding acts for continuity, the current text of Act 2, and your exact idea — then shows you the old and new versions side by side. Nothing is overwritten until you press Use New. If you press Keep Old instead, nothing changes at all.

🟢 Common mistakes

  • 🔵Leaving the Story Bible fields empty — without a locked character list and setting, later acts can drift and invent new names.
  • 🟠Splitting into very small parts (under 50 words) — short chunks lose surrounding context and regenerate awkwardly.
  • 🟣Forgetting to press Merge Parts Back Into Story after editing in the Parts tab, then exporting the old, unedited Story tab text.

🔴 Honest limitations

This is not a fully offline tool — generating and regenerating text calls your chosen AI provider over the internet, using your own API key. The forbidden-word scanner catches exact matches only, so a rephrased problem word can slip through; always read a section before exporting it. Read Aloud uses your browser’s own Web Speech API, so voice quality and language support depend on your browser, not on the tool. And like any AI writer, it can repeat a phrase or lose a small detail across a very long story — the version history exists precisely so a bad regeneration never costs you the good draft you already had.

To turn a finished script into shot-by-shot visual prompts, pair this with the AI Story-to-Storyboard Generator . For the idea behind the Undo/Compare feature, see How Undo and Redo Work: Version History as a Stack .

Last updated: September 2026

🤔 Frequently asked questions

Where is my API key stored?

Only in your own browser’s local storage. It is sent directly from your browser to your chosen provider and never passes through any other server.

Which AI providers can this AI story generator use?

Google Gemini, OpenAI or Anthropic — pick one, enter your own key and model name, and switch providers any time.

Can I import a script I already wrote?

Yes. Paste it or upload a .txt/.md file, choose how many acts to split it into, and it becomes fully editable with the same regenerate and undo tools.

How many past versions can I recover?

The last three versions of each section are kept. Restoring one pushes the current text back into that history, so you can go back and forth safely.

Does it check for unsafe or overly graphic wording?

Yes — sections are scanned against a forbidden-word list you can extend through your own instruction, and any flagged line can be rewritten on its own with one click.

What’s the difference between the Story tab and the Parts tab?

Story holds the four main acts. Parts breaks the whole story into smaller, sentence-safe sections for finer editing — merge them back into Story when you’re done.

Is my story saved if I close the tab?

Yes, it stays in your browser’s local storage under the Story Library until you delete that project or clear your browser data.