Brain Dump Organizer (Auto-Sorts Ideas)
Here's a lightweight brain dump tool for story writers. You paste raw thoughts (messy is fine), hit one button, and it auto-organizes your notes into buckets like Characters, Plot, Worldbuilding, Scenes, Dialogue, and Loose Ideas.
Why it’s useful: The hardest part is getting the ideas out of your head. This tool is designed for speed: dump first, organize second. It doesn’t try to be a full writing app — it’s a fast “thinking scratchpad” that turns chaos into structure.
What it does:
- Paste or type a brain dump (one thought per line, or paragraphs).
- Auto-tags each line into categories using simple rules (keywords + patterns).
- Highlights lines that look like character names, scene beats, or dialogue.
- Saves everything in your browser (
localStorage) — no database, no login. - Export organized notes to a single clean block you can paste into your doc.
Install:
- Create:
/tools/story-organizer/ - Save as:
/tools/story-organizer/index.html - Visit:
/tools/story-organizer/
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Story Brain Dump Organizer</title>
<meta name="description" content="Dump your story ideas and auto-organize them into characters, plot, world, scenes, dialogue, and loose ideas. Lightweight, no login." />
<meta name="robots" content="index,follow" />
<link rel="canonical" href="https://your-site.com/tools/story-organizer/" />
<style>
:root{
--bg:#0b0f16; --panel:#111a26; --panel2:#0c1420;
--text:#e8eef8; --muted:rgba(232,238,248,.72);
--line:rgba(255,255,255,.10); --accent:#2a8cff;
--shadow:0 18px 55px rgba(0,0,0,.45); --r:16px;
--ok:#7CFF9A; --warn:#FFD37C;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);
font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif}
.wrap{max-width:1200px;margin:0 auto;padding:18px}
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
padding:14px;margin:12px 0;box-shadow:var(--shadow)}
.top{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;align-items:center}
.pill{display:inline-block;padding:4px 10px;border-radius:999px;
background:rgba(42,140,255,.14);border:1px solid rgba(42,140,255,.25);
font-weight:900;font-size:12px}
.muted{color:var(--muted)}
.grid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:12px}
.c5{grid-column:span 5}
.c7{grid-column:span 7}
.c12{grid-column:span 12}
@media(max-width:980px){.c5,.c7{grid-column:span 12}}
textarea{
width:100%;min-height:320px;resize:vertical;padding:10px 12px;
border-radius:14px;border:1px solid var(--line);background:var(--panel2);
color:var(--text);outline:none;
font:650 13px/1.45 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
input{
width:100%;padding:10px 12px;border-radius:12px;border:1px solid var(--line);
background:var(--panel2);color:var(--text);outline:none;font-weight:800;
}
.btn{
display:inline-flex;align-items:center;justify-content:center;gap:8px;
border:0;border-radius:12px;padding:10px 12px;background:var(--accent);
color:#06101a;font-weight:950;cursor:pointer;
}
.btn2{
display:inline-flex;align-items:center;justify-content:center;gap:8px;
border:1px solid var(--line);border-radius:12px;padding:10px 12px;background:transparent;
color:var(--text);font-weight:950;cursor:pointer;
}
.row{display:flex;gap:10px;flex-wrap:wrap}
.bucket{
border:1px solid rgba(255,255,255,.10);
background:rgba(255,255,255,.03);
border-radius:16px;padding:12px;
}
.bucket h3{margin:0 0 8px;font-size:14px}
.item{
padding:8px 10px;border-radius:12px;border:1px solid rgba(255,255,255,.08);
background:rgba(0,0,0,.18);margin:8px 0;white-space:pre-wrap;
}
.tag{
display:inline-block;margin-left:8px;font-size:11px;font-weight:950;
padding:2px 8px;border-radius:999px;border:1px solid rgba(255,255,255,.14);
background:rgba(255,255,255,.05);color:var(--muted)
}
.hr{height:1px;background:var(--line);margin:12px 0}
.small{font-size:12px}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
.out{
min-height:220px;padding:12px;border-radius:14px;border:1px solid var(--line);
background:var(--panel2);white-space:pre-wrap;word-break:break-word;
font:650 13px/1.45 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
</style>
</head>
<body>
<div class="wrap">
<div class="card">
<div class="top">
<div>
<div class="pill">Writer Tool</div>
<h1 style="margin:10px 0 6px;font-size:22px">Story Brain Dump Organizer</h1>
<div class="muted">Dump ideas fast → auto-sort into buckets → export a clean outline.</div>
</div>
<div class="row">
<button class="btn" id="organize" type="button">🧠 Organize</button>
<button class="btn2" id="copyExport" type="button">📋 Copy Export</button>
<button class="btn2" id="save" type="button">💾 Save</button>
<button class="btn2" id="clear" type="button">🧹 Clear</button>
</div>
</div>
<div class="hr"></div>
<div class="grid">
<div class="c5">
<div class="muted small" style="margin-bottom:6px">Project title (optional)</div>
<input id="title" placeholder="e.g. Neon Witch Detective" />
</div>
<div class="c7">
<div class="muted small" style="margin-bottom:6px">Quick tip</div>
<div class="muted small" style="line-height:1.5">
One thought per line works best. Dialogue lines can start with quotes:
<span class="mono">"I didn't come here to forgive you."</span>
</div>
</div>
</div>
</div>
<div class="grid">
<div class="card c5">
<b>Brain dump</b>
<div class="muted small" style="margin:6px 0 10px">
Paste everything. Messy is the point.
</div>
<textarea id="dump" placeholder="She hides a map in a library book.
Main character: Riven, ex-paramedic turned smuggler.
The city is built inside a dead spaceship.
\"Don't say my name.\" (dialogue)
Ending: they realize the villain is future-them."></textarea>
</div>
<div class="card c7">
<b>Organized buckets</b>
<div class="muted small" style="margin:6px 0 10px">
This uses simple rules (keywords + patterns). You can tweak the keyword lists in the script.
</div>
<div class="grid">
<div class="c6">
<div class="bucket">
<h3>Characters</h3>
<div id="b_char"></div>
</div>
</div>
<div class="c6">
<div class="bucket">
<h3>Plot & Stakes</h3>
<div id="b_plot"></div>
</div>
</div>
<div class="c6">
<div class="bucket">
<h3>Worldbuilding</h3>
<div id="b_world"></div>
</div>
</div>
<div class="c6">
<div class="bucket">
<h3>Scenes & Beats</h3>
<div id="b_scenes"></div>
</div>
</div>
<div class="c6">
<div class="bucket">
<h3>Dialogue</h3>
<div id="b_dialogue"></div>
</div>
</div>
<div class="c6">
<div class="bucket">
<h3>Loose Ideas</h3>
<div id="b_misc"></div>
</div>
</div>
<div class="c12">
<div class="bucket">
<h3>Export (clean outline)</h3>
<div class="out" id="export"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
(function(){
var KEY = "storyOrganizer:v1";
function $(id){ return document.getElementById(id); }
function lines(s){
// split by lines, but also break big paragraphs into sentences-ish if needed
var raw = String(s||"").replace(/\r/g,"").trim();
if (!raw) return [];
var arr = raw.split("\n").map(function(x){ return x.trim(); }).filter(Boolean);
// if someone pasted one giant paragraph, try a gentle split
if (arr.length <= 2 && raw.length > 240) {
arr = raw.split(/(?<=[\.\!\?])\s+/).map(function(x){ return x.trim(); }).filter(Boolean);
}
return arr;
}
function uniq(arr){
var seen = Object.create(null), out=[];
arr.forEach(function(x){
var k = x.toLowerCase();
if (seen[k]) return;
seen[k]=1; out.push(x);
});
return out;
}
// Simple rule sets (edit these to fit your vibe)
var RULES = {
characters: [
"main character","protagonist","antagonist","villain","hero","sidekick","mentor",
"sister","brother","mother","father","friend","rival",
"named","character:","mc","npc"
],
plot: [
"goal","wants","must","stakes","conflict","problem","twist","reveal","betrayal",
"ending","finale","climax","mystery","secret","deadline","plan","fails","wins","loss"
],
world: [
"world","setting","city","kingdom","planet","space","school","timeline","future","past",
"magic","rules","technology","law","religion","culture","economy","species","faction"
],
scenes: [
"scene","chapter","beat","cold open","opening","montage","cut to","later","flashback",
"fight","chase","heist","interrogation","break-in","escape","meet","kiss","argument"
]
};
function looksLikeDialogue(s){
s = s.trim();
if (!s) return false;
if (s.startsWith('"') && s.endsWith('"')) return true;
if (s.startsWith("“") && s.endsWith("”")) return true;
// NAME: "..."
if (/^[A-Z][A-Z0-9 _-]{1,20}:\s*["“]/.test(s)) return true;
return false;
}
function looksLikeCharacterLine(s){
// Heuristic: "Name:" or "Main character: X" or "Character: X"
if (/^(main character|character|protagonist|antagonist)\s*:/i.test(s)) return true;
// A single capitalized name with descriptor
if (/^[A-Z][a-z]+(\s+[A-Z][a-z]+)?\s*[-–—:]/.test(s)) return true;
return false;
}
function matchAny(s, words){
var low = s.toLowerCase();
for (var i=0;i<words.length;i++){
if (low.indexOf(words[i]) !== -1) return true;
}
return false;
}
function tagLine(s){
if (looksLikeDialogue(s)) return {bucket:"dialogue", tag:"dialogue"};
if (looksLikeCharacterLine(s) || matchAny(s, RULES.characters)) return {bucket:"char", tag:"character"};
if (matchAny(s, RULES.plot)) return {bucket:"plot", tag:"plot"};
if (matchAny(s, RULES.world)) return {bucket:"world", tag:"world"};
if (matchAny(s, RULES.scenes)) return {bucket:"scenes", tag:"scene"};
return {bucket:"misc", tag:"idea"};
}
function renderBucket(id, arr, tag){
var host = $(id);
host.innerHTML = "";
if (!arr.length){
host.innerHTML = '<div class="muted small">—</div>';
return;
}
arr.forEach(function(x){
var div = document.createElement("div");
div.className = "item";
div.textContent = x;
var t = document.createElement("span");
t.className = "tag";
t.textContent = tag;
div.appendChild(t);
host.appendChild(div);
});
}
function buildExport(title, buckets){
function section(name, arr){
if (!arr.length) return "";
return name + ":\n" + arr.map(function(x){ return "- " + x; }).join("\n") + "\n\n";
}
var out = "";
if (title) out += title + "\n" + "=".repeat(Math.min(40, Math.max(6, title.length))) + "\n\n";
out += section("Characters", buckets.char);
out += section("Plot & Stakes", buckets.plot);
out += section("Worldbuilding", buckets.world);
out += section("Scenes & Beats", buckets.scenes);
out += section("Dialogue", buckets.dialogue);
out += section("Loose Ideas", buckets.misc);
return out.trim();
}
function organize(){
var t = $("title").value.trim();
var dump = $("dump").value;
var arr = lines(dump);
arr = uniq(arr);
var buckets = {char:[], plot:[], world:[], scenes:[], dialogue:[], misc:[]};
arr.forEach(function(line){
var r = tagLine(line);
buckets[r.bucket].push(line);
});
// Render
renderBucket("b_char", buckets.char, "character");
renderBucket("b_plot", buckets.plot, "plot");
renderBucket("b_world", buckets.world, "world");
renderBucket("b_scenes", buckets.scenes, "scene");
renderBucket("b_dialogue", buckets.dialogue, "dialogue");
renderBucket("b_misc", buckets.misc, "idea");
$("export").textContent = buildExport(t, buckets);
}
function save(){
var obj = {title:$("title").value, dump:$("dump").value};
localStorage.setItem(KEY, JSON.stringify(obj));
alert("Saved (local).");
}
function load(){
try{
var j = JSON.parse(localStorage.getItem(KEY) || "");
if (!j) return;
$("title").value = j.title || "";
$("dump").value = j.dump || "";
} catch(e){}
}
function clearAll(){
if (!confirm("Clear your brain dump?")) return;
$("dump").value = "";
$("export").textContent = "";
["b_char","b_plot","b_world","b_scenes","b_dialogue","b_misc"].forEach(function(id){
$(id).innerHTML = '<div class="muted small">—</div>';
});
}
function copyExport(){
var txt = $("export").textContent || "";
if (!txt.trim()) return;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(txt).catch(function(){ fallbackCopy(txt); });
} else fallbackCopy(txt);
}
function fallbackCopy(t){
var ta = document.createElement("textarea");
ta.value = t;
document.body.appendChild(ta);
ta.select();
document.execCommand("copy");
document.body.removeChild(ta);
}
$("organize").addEventListener("click", organize);
$("save").addEventListener("click", save);
$("clear").addEventListener("click", clearAll);
$("copyExport").addEventListener("click", copyExport);
load();
// auto-organize when there’s content
if ($("dump").value.trim()) organize();
})();
</script>
</body>
</html>
Comments (0)
No comments yet — be the first.