Programming

BBCode Generator : Local Playground ( tforum tool )

Started by gadgqf3t1cvaca · Oct 27, 2025

#11364
This tool will allow you to quickly and easily generate posts with cool gradients like this

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>

#11365
↳ Replying to @gadgqf3t1cvaca
Very interesting. I have been THINKING of making something like this for the past few months, but kept procrastinating.

Lmfao well you've done it :) I will try to find solutions on whether I can make this not require JS

And I'll see if I can make this into a website so others can utilize it, thanks a lot :))
#11366
↳ Replying to @Trojan
its definitely feasible to not require JS on the front-end , not such a bad idea for a multi tool website , if it was a hidden service i would personally save the link

the reason i am choosing this format is to allow people to use it offline locally without worrying someone might be logging their activity and running simple tools like this one isolated offline might be the optimal for some users, thank you for your comment:)
#11368
↳ Replying to @the_baker
copy the entire code from the post , create a bbcode.html file on your machine , modify the html file and paste the code, save the file , open the file in any browser ( no internet required )
#11372
↳ Replying to @B4rr4cks
and you?

Are you challenging me to a duel?

. .~ Peace ~

~ ❄️ Chip ❄️~


I use it primarily for my signature, which I've been doing it that way since before tforum.

I save it's use for reviews. It has more effect that way.