you can choose between various patterns
or quickly create
❖━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━❖
structural elements in your posts
╔══════════════════════════════════════╗
Here's the code you can run locally offline
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>BBCode Workshop [Final]</title><style>:root{--bg:#1a1c20;--bg-light:#2a2d33;--bg-lighter:#3c4047;--fg:#e0e2e5;--fg-muted:#9ba1aa;--accent:#0095ff;--accent-glow:rgba(0,149,255,.15);--border-color:#3c4047;--success:#28a745}*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;background-color:var(--bg);color:var(--fg);line-height:1.6;padding:20px}.container{max-width:1400px;margin:0 auto;display:grid;grid-template-columns:1fr;gap:30px}header{text-align:center;border-bottom:1px solid var(--border-color);padding-bottom:20px}header h1{font-size:2.5em}header p{color:var(--fg-muted);font-size:1.1em}section{background-color:var(--bg-light);border:1px solid var(--border-color);border-radius:12px;padding:24px}h2{font-size:1.8em;margin-bottom:20px;border-bottom:1px solid var(--border-color);padding-bottom:10px}.form-group{margin-bottom:20px}label{display:block;margin-bottom:8px;font-weight:600;color:var(--fg-muted)}input,textarea,select{width:100%;padding:12px;background-color:var(--bg);border:1px solid var(--border-color);border-radius:8px;color:var(--fg);font-size:14px;transition:all .2s}textarea{resize:vertical;font-family:Consolas,"Courier New",monospace}input:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-glow)}button{padding:10px 20px;border:1px solid var(--border-color);background-color:var(--bg-lighter);color:var(--fg);border-radius:8px;cursor:pointer;font-weight:600;font-size:1em;transition:all .2s}button:hover{background-color:#4a4e56;transform:translateY(-1px)}button.copied{background-color:var(--success)!important;color:#fff}.controls,.button-bar,.checkbox-bar{display:flex;flex-wrap:wrap;gap:10px;align-items:center}.preview-box{margin-top:15px;padding:15px;border-radius:8px;border:1px dashed var(--border-color);background-color:var(--bg);min-height:40px;white-space:pre-wrap;word-wrap:break-word;font-size:1em;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}.preview-box h1,.preview-box h2{border:none;margin:.5em 0}.preview-box h1{font-size:1.5em}.preview-box h2{font-size:1.25em}.preview-box table{width:100%;border-collapse:collapse;margin:1em 0}.preview-box th,.preview-box td{border:1px solid var(--border-color);padding:8px;text-align:left}.preview-box th{background-color:var(--bg-lighter)}.preview-box blockquote{background-color:var(--bg);border-left:3px solid var(--accent);padding:10px 15px;margin:1em 0}.preview-box blockquote cite{display:block;font-style:italic;color:var(--fg-muted);margin-bottom:5px}.preview-box pre{background-color:#111;padding:10px;border-radius:5px;white-space:pre-wrap;word-break:break-all}.preview-box ul{margin:1em 0;padding-left:20px}.output-area{position:relative}.copy-btn{position:absolute;top:10px;right:10px;background-color:rgba(0,0,0,.3);padding:5px 10px;font-size:.8em}.tool-grid{display:grid;grid-template-columns:1fr 1fr;gap:30px}details{border-bottom:1px solid var(--border-color);padding-bottom:10px;margin-bottom:10px}details>summary{cursor:pointer;font-size:1.8em;list-style:none}details>summary::-webkit-details-marker{display:none}details>summary::before{content:'▶';display:inline-block;margin-right:12px;font-size:.7em;transition:transform .2s}details[open]>summary::before{transform:rotate(90deg)}.hidden{display:none}@media (max-width:900px){.tool-grid{grid-template-columns:1fr}}</style></head><body><div class="container"><header><h1>BBCode Workshop</h1><p>The definitive toolkit for crafting advanced BBCode.</p></header><section><h2>Composer</h2><div class="button-bar form-group"><button onclick="w('mainComposer','b')">Bold</button><button onclick="w('mainComposer','i')">Italic</button><button onclick="w('mainComposer','s')">Strike</button><button onclick="w('mainComposer','center')">Center</button><button onclick="w('mainComposer','title')">Title</button><button onclick="w('mainComposer','subtitle')">Subtitle</button><button onclick="s('mainComposer','url')">URL</button><button onclick="s('mainComposer','quote')">Quote</button><button onclick="s('mainComposer','list')">List</button><button onclick="w('mainComposer','code')">Code</button></div><div class="output-area"><textarea id="mainComposer" rows="15" placeholder="Compose your masterpiece here..."></textarea><button class="copy-btn" onclick="c('mainComposer',this)">Copy Full Text</button></div><div class="preview-box" id="mainComposerPreview"><span style="color:var(--fg-muted)">Live preview will render here as you type...</span></div></section><div class="tool-grid"><details open><summary><h2>Advanced Gradient Text</h2></summary><div class="form-group"><label for="inputText">Text</label><textarea id="inputText" rows="3" placeholder="Enter text..."></textarea></div><div class="controls"><div class="form-group" style="flex-grow:1;margin-bottom:0"><label for="colorPalette">Palette</label><select id="colorPalette"><option value="subtle-blue">Subtle Blue</option><option value="emerald-green">Emerald Green</option><option value="muted-purple">Muted Purple</option><option value="warm-gold">Warm Gold</option><option value="cool-gray">Cool Gray</option><option value="fire-red">Fire Red</option><option value="black-white">Black-White</option></select></div><div class="form-group" style="flex-grow:1;margin-bottom:0"><label for="gradientType">Style</label><select id="gradientType"><option value="linear">Linear</option><option value="symmetrical">Symmetrical</option><option value="wave">Wave (Sine)</option><option value="per-word">Per Word</option></select></div></div><div class="form-group hidden" id="waveLengthGroup"><label for="waveLength">Wave Length (Chars)</label><input type="number" id="waveLength" value="10" min="2"></div><div class="form-group"><label for="highlightChars">Highlight Characters (Uses Brightest Color)</label><input type="text" id="highlightChars" placeholder="e.g., ABC[]❖"></div><div class="preview-box" id="gradientPreview"></div><div class="output-area form-group" style="margin-top:20px"><label for="bbcodeOutput">Result</label><textarea id="bbcodeOutput" rows="5" readonly></textarea><button class="copy-btn" onclick="c('bbcodeOutput',this)">Copy</button></div><div class="checkbox-bar"><label>Wrap Result:</label><input type="checkbox" id="wrapB"><label for="wrapB">Bold</label><input type="checkbox" id="wrapI"><label for="wrapI">Italic</label><input type="checkbox" id="wrapC"><label for="wrapC">Center</label></div></details><details><summary><h2>Structural Elements</h2></summary><div class="form-group"><label>Styled Divider Generator</label><div class="controls"><input type="text" id="divStartCap" value="❖" title="Start Cap" style="width:50px;text-align:center"><input type="text" id="divMidChar" value="━" title="Middle Character" style="flex-grow:1;text-align:center"><input type="text" id="divEndCap" value="❖" title="End Cap" style="width:50px;text-align:center"><input type="number" id="divLength" value="12" min="1" title="Middle Length" style="width:70px"></div></div><div class="preview-box" id="dividerPreview"></div><div class="output-area form-group" style="margin-top:20px"><label for="dividerOutput">Result</label><textarea id="dividerOutput" rows="5" readonly></textarea><button class="copy-btn" onclick="c('dividerOutput',this)">Copy</button></div><div class="form-group"><label>Table Generator</label><div class="controls"><input type="number" id="tableRows" value="4" min="1" title="Rows"><input type="number" id="tableCols" value="3" min="1" title="Columns"><button id="generateTableBtn" style="flex-grow:1">Generate Table</button></div><div class="checkbox-bar"><input type="checkbox" id="tableHeader" checked style="width:auto"><label for="tableHeader">First row is a header</label></div></div><div class="output-area"><textarea id="tableOutput" rows="8" readonly></textarea><button class="copy-btn" onclick="c('tableOutput',this)">Copy</button></div></details></div></div><script>const P={'subtle-blue':['#456274','#5F7A8F','#6C869D'],'emerald-green':['#145A32','#27AE60','#A9DFBF'],'muted-purple':['#512E5F','#7D3C98','#A569BD'],'warm-gold':['#B7791F','#F39C12','#FDEBD0'],'cool-gray':['#566573','#808B96','#D5D8DC'],'fire-red':['#943126','#E74C3C','#F5B7B1'],'black-white':['#1C1C1C','#808080','#FFFFFF']},HTR=h=>{const r=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(h);return r?{r:parseInt(r[1],16),g:parseInt(r[2],16),b:parseInt(r[3],16)}:null},RTH=(r,g,b)=>"#"+((1<<24)+(r<<16)+(g<<8)+b).toString(16).slice(1).toUpperCase(),L=(a,b,t)=>a+t*(b-a);function getGradientColor(o,e){const[t,l,r]=[HTR(e[0]),HTR(e[1]),HTR(e[2])],a=o<.5?2*o:2*(o-.5),[n,d]=o<.5?[t,l]:[l,r];return RTH(Math.round(L(n.r,d.r,a)),Math.round(L(n.g,d.g,a)),Math.round(L(n.b,d.b,a)))}function generateGradient(o,e,t,l={}){let r={bbcode:"",html:""};if(!o)return r;const a=n=>{let d={bbcode:"",html:""};const i=n.length;for(let o=0;o<i;o++){if(l.highlights&&l.highlights.includes(n[o])){const t=e[2];d.bbcode+=`[color=${t}]${n[o]}[/color]`,d.html+=`<span style="color:${t}">${n[o].replace(/</g,"<")}</span>`;continue}let r;switch(t){case"symmetrical":r=i>1?o<i/2?o/(i-1)*2:(i-1-o)/(i-1)*2:0;break;case"wave":r=(Math.sin(o/(l.waveLength-1)*2*Math.PI)+1)/2;break;default:r=i>1?o/(i-1):0}const a=getGradientColor(r,e);d.bbcode+=`[color=${a}]${n[o]}[/color]`,d.html+=`<span style="color:${a}">${n[o].replace(/</g,"<")}</span>`}return d};if("per-word"===t)o.split(/(\s+)/).forEach(o=>{if(/\s+/.test(o))r.bbcode+=o,r.html+=o;else{const e=a(o);r.bbcode+=e.bbcode,r.html+=e.html}});else r=a(o);return l.wrapB&&(r.bbcode=`${r.bbcode}`,r.html=`<b>${r.html}</b>`),l.wrapI&&(r.bbcode=`${r.bbcode}`,r.html=`<i>${r.html}</i>`),l.wrapC&&(r.bbcode=`[center]${r.bbcode}[/center]`,r.html=`<div style="text-align:center">${r.html}</div>`),r}function parseBBCode(o){o=o.replace(/</g,"<").replace(/>/g,">");const e=[{r:/\[b\]((.|\n)*?)\[\/b\]/gi,t:"<b>$1</b>"},{r:/\[i\]((.|\n)*?)\[\/i\]/gi,t:"<i>$1</i>"},{r:/\[s\]((.|\n)*?)\[\/s\]/gi,t:"<s>$1</s>"},{r:/\[title\]((.|\n)*?)\[\/title\]/gi,t:"<h1>$1</h1>"},{r:/\[subtitle\]((.|\n)*?)\[\/subtitle\]/gi,t:"<h2>$1</h2>"},{r:/\[center\]((.|\n)*?)\[\/center\]/gi,t:'<div style="text-align:center">$1</div>'},{r:/\[color=([#\w]+)\]((.|\n)*?)\[\/color\]/gi,t:'<span style="color:$1">$2</span>'},{r:/\]+)\]((.|\n)*?)\[\/url\]/gi,t:'<a href="$1" target="_blank">$2</a>'},{r:/\[url\]((.|\n)*?)\[\/url\]/gi,t:'<a href="$1" target="_blank">$1</a>'},{r:/\([^\ wrote:]+)\]((.|\n)*?)\[\/quote\]/gi,t:"<blockquote><cite>$1 wrote:</cite>$2</blockquote>"},{r:/\[quote\]((.|\n)*?)\[\/quote\]/gi,t:"<blockquote>$1</blockquote>"},{r:/\[code\]((.|\n)*?)\[\/code\]/gi,t:"<pre>$1</pre>"},{r:/\[table\]((.|\n)*?)\[\/table\]/gi,t:"<table>$1</table>"},{r:/\[tr\]((.|\n)*?)\[\/tr\]/gi,t:"<tr>$1</tr>"},{r:/\[th\]((.|\n)*?)\[\/th\]/gi,t:"<th>$1</th>"},{r:/\[td\]((.|\n)*?)\[\/td\]/gi,t:"<td>$1</td>"}];return o=o.replace(/\[list\]((.|\n)*?)\[\/list\]/gi,((o,e)=>`<ul>${e.trim().split("\n").map(o=>`<li>${o.trim()}</li>`).join("")}</ul>`)),e.forEach(e=>{o=o.replace(e.r,e.t)}),o.replace(/\n/g,"<br>")}function w(o,e){const t=document.getElementById(o),[l,r]=[t.selectionStart,t.selectionEnd];t.value=`${t.value.substring(0,l)}[${e}]${t.value.substring(l,r)}[/${e}]${t.value.substring(r)}`,t.dispatchEvent(new Event("input"))}function s(o,e){const t=document.getElementById(o),[l,r]=[t.selectionStart,t.selectionEnd];const a=t.value.substring(l,r);let n="";switch(e){case"url":const o=prompt("Enter URL:","http://");if(!o)return;n=`[url=${o}]${a||o}`;break;case"quote":const d=prompt("Enter author (optional):");n=d?`[quote=${d}]${a}
`:`${a}
`;break;case"list":const i=a.split("\n").filter(o=>o.trim()).join("\n");if(!i)return alert("Select text for list (one item per line).");n=`- \n${i}\n
`}t.value=`${t.value.substring(0,l)}${n}${t.value.substring(r)}`,t.dispatchEvent(new Event("input"))}function generateTable(){const[o,e,t]=[parseInt(ui.tableRows.value),parseInt(ui.tableCols.value),ui.tableHeader.checked];let l="[table]\n";for(let r=0;r<o;r++){l+="[tr]\n";for(let o=0;o<e;o++)l+=r===0&&t?"[th] [/th]":"[td] [/td]";l+="\n[/tr]\n"}ui.tableOutput.value=l+"[/table]"}function c(o,e){const t=document.getElementById(o);if(!t.value)return;navigator.clipboard.writeText(t.value).then(()=>{const o=e.textContent;e.textContent="Copied!",e.classList.add("copied"),setTimeout(()=>{e.textContent=o,e.classList.remove("copied")},1500)})}const ui=Object.fromEntries([...document.querySelectorAll("[id]")].map(o=>[o.id,o]));document.addEventListener("DOMContentLoaded",()=>{const o=()=>{const o=generateGradient(ui.inputText.value,P[ui.colorPalette.value],ui.gradientType.value,{waveLength:parseInt(ui.waveLength.value),highlights:ui.highlightChars.value,wrapB:ui.wrapB.checked,wrapI:ui.wrapI.checked,wrapC:ui.wrapC.checked});ui.waveLengthGroup.classList.toggle("hidden","wave"!==ui.gradientType.value),ui.bbcodeOutput.value=o.bbcode,ui.gradientPreview.innerHTML=o.html},e=()=>{const o=`${ui.divStartCap.value}${ui.divMidChar.value.repeat(parseInt(ui.divLength.value))}${ui.divEndCap.value}`,e=generateGradient(o,P[ui.colorPalette.value],"symmetrical");ui.dividerOutput.value=e.bbcode,ui.dividerPreview.innerHTML=e.html};ui.mainComposer.addEventListener("input",()=>{ui.mainComposerPreview.innerHTML=parseBBCode(ui.mainComposer.value)||'<span style="color: var(--fg-muted)">Live preview will render here...</span>'}),[...document.querySelectorAll("#inputText, #colorPalette, #gradientType, #waveLength, #highlightChars, #wrapB, #wrapI, #wrapC")].forEach(e=>e.addEventListener("input",o)),[...document.querySelectorAll("#divStartCap, #divMidChar, #divEndCap, #divLength, #colorPalette")].forEach(o=>o.addEventListener("input",e)),[...document.querySelectorAll("#tableRows, #tableCols, #tableHeader, #generateTableBtn")].forEach(o=>o.addEventListener("input",generateTable)),ui.generateTableBtn.addEventListener("click",generateTable),o(),e(),generateTable()});</script></body></html>