Slop-Index-Lite / index.html
Vibeaxis's picture
Update index.html
789f362 verified
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Slop Index Lite — VibeAxis</title>
<meta name="description" content="Quick, client-side 'slop' detector for text. Checks clichés, hedges, filler, repetition, and sentence bloat.">
<style>
:root{--bg:#0b0b0c;--fg:#eee;--mut:#9aa0a6;--card:#141518;--acc:#ffd400}
*{box-sizing:border-box} html,body{height:100%} body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.5 system-ui,-apple-system,Segoe UI,Roboto,Inter,Arial}
.wrap{max-width:920px;margin:32px auto;padding:0 16px}
h1{font-size:28px;margin:0 0 6px} .tag{color:var(--mut);font-size:14px;margin-bottom:18px}
.card{background:var(--card);border:1px solid #1f2024;border-radius:16px;padding:16px;margin:16px 0}
textarea{width:100%;min-height:220px;background:#0f1013;color:var(--fg);border:1px solid #25262b;border-radius:10px;padding:12px;resize:vertical;font:14px/1.45 ui-monospace,SFMono-Regular,Consolas,Monaco,monospace}
.row{display:flex;gap:12px;flex-wrap:wrap;margin:12px 0}
.btn{background:var(--acc);color:#000;border:0;border-radius:999px;padding:10px 14px;font-weight:700;cursor:pointer}
.btn.subtle{background:#1b1c20;color:var(--fg);border:1px solid #2a2b30}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.metric{background:#0f1013;border:1px solid #25262b;border-radius:12px;padding:12px}
.metric b{display:block;font-size:22px;margin-bottom:6px}
.bar{height:8px;border-radius:999px;background:#1e2025;overflow:hidden}
.fill{height:100%;width:0;background:linear-gradient(90deg,#ff7a7a,#ffb37a)}
a{color:var(--acc);text-decoration:none} a:hover{text-decoration:underline}
.note{color:var(--mut);font-size:13px;margin-top:8px}
</style>
</head>
<body>
<div class="wrap">
<h1>Slop Index Lite</h1>
<div class="tag">Fast, client-side gut check for filler, hedging, clichés, and repetition. No upload. No storage.</div>
<div class="card">
<textarea id="txt" placeholder="Paste text here…"></textarea>
<div class="row">
<button class="btn" id="analyze">Analyze</button>
<button class="btn subtle" id="sample">Try Sample</button>
</div>
<div class="note">Heads-up: this is a heuristic demo. For the deep dive and full signal set, see the article on VibeAxis.</div>
</div>
<div class="grid">
<div class="metric"><b id="score"></b>Slop Score (0–100)<div class="bar"><div class="fill" id="fill"></div></div></div>
<div class="metric"><b id="uniq">–%</b>Uniqueness (type/token)</div>
<div class="metric"><b id="bloat"></b>Avg sentence length</div>
<div class="metric"><b id="hedge"></b>Hedge words</div>
<div class="metric"><b id="cliche"></b>Clichés</div>
<div class="metric"><b id="ly"></b>“-ly” adverbs</div>
<div class="metric"><b id="repeat"></b>Top word repeats</div>
</div>
<div class="card" id="findings" style="display:none"></div>
<div class="card">
<b>Receipts / Learn More</b><br/>
<a href="https://vibeaxis.com" target="_blank" rel="noopener">VibeAxis</a> — article & methodology (link to your tool post)<br/>
</div>
</div>
<script>
(function(){
const hedges = ['perhaps','maybe','seems','appears','arguably','reportedly','somewhat','kind of','sort of','likely','unlikely','possibly','generally','in my opinion','i think','we believe'];
const cliches = ['at the end of the day','paradigm shift','game changer','leverage','cutting edge','world class','next generation','best in class','innovative solution','seamless experience','move the needle','win-win','low-hanging fruit'];
const stop = new Set(['the','a','an','and','or','but','of','to','in','on','for','with','as','by','is','are','was','were','it','that','this','be','from','at','we','you','they','i']);
const $ = s=>document.querySelector(s);
const txt = $('#txt'), out = {
score: $('#score'), uniq: $('#uniq'), bloat: $('#bloat'),
hedge: $('#hedge'), cliche: $('#cliche'), ly: $('#ly'), repeat: $('#repeat'),
fill: $('#fill'), findings: $('#findings')
};
function sentences(s){
return s.split(/(?<=[\.\?\!])\s+/).map(x=>x.trim()).filter(Boolean);
}
function words(s){
return s.toLowerCase().replace(/[^a-z0-9\s'-]+/g,' ').split(/\s+/).filter(Boolean);
}
function topRepeats(tokens, n=3){
const freq = Object.create(null);
tokens.forEach(t=>{ if(!stop.has(t)) freq[t]=(freq[t]||0)+1; });
return Object.entries(freq).sort((a,b)=>b[1]-a[1]).slice(0,n);
}
function analyze(){
const raw = txt.value || '';
const sents = sentences(raw);
const toks = words(raw);
const uniq = new Set(toks).size;
const ttr = toks.length ? (uniq / toks.length) : 0;
const avgLen = sents.length ? (toks.length / sents.length) : 0;
const hedgeCount = hedges.reduce((n,h)=> n + (raw.toLowerCase().includes(h) ? 1 : 0), 0);
const clicheCount = cliches.reduce((n,h)=> n + (raw.toLowerCase().includes(h) ? 1 : 0), 0);
const lyCount = (raw.match(/\b\w+ly\b/gi) || []).length;
const repeats = topRepeats(toks, 3);
const repScore = repeats.reduce((n,[_w,c])=> n + Math.max(0,c-2), 0);
// Slop score (higher = worse): bloat + hedges + clichés + adverbs + repeats – uniqueness bonus
let score = 0;
score += Math.max(0, avgLen - 22) * 1.2; // sentence bloat
score += hedgeCount * 5; // hedging
score += clicheCount * 6; // clichés
score += Math.max(0, lyCount - 4) * 1.2; // adverb pileup
score += repScore * 2.5; // repetition
score += (1 - Math.min(1, ttr*1.25)) * 20; // low uniqueness
score = Math.max(0, Math.min(100, Math.round(score)));
// UI
out.score.textContent = String(score);
out.fill.style.width = score + '%';
out.uniq.textContent = Math.round(ttr*100)+'%';
out.bloat.textContent = sents.length? avgLen.toFixed(1) : '–';
out.hedge.textContent = hedgeCount;
out.cliche.textContent = clicheCount;
out.ly.textContent = lyCount;
out.repeat.textContent = repeats.map(([w,c])=> w+'×'+c).join(', ') || '–';
// Findings
const bullets = [];
if (avgLen > 24) bullets.push('Long sentences — consider splitting.');
if (hedgeCount) bullets.push('Hedging language detected (confidence fog).');
if (clicheCount) bullets.push('Cliché phrases detected (corporate slop).');
if (lyCount > 6) bullets.push('Adverb pile-up (try stronger verbs).');
if (ttr < 0.4) bullets.push('Low uniqueness — repetition or boilerplate.');
if (!bullets.length) bullets.push('Looks fairly tight. Try a tougher sample.');
out.findings.style.display = 'block';
out.findings.innerHTML = '<b>Highlights</b><ul style="margin:8px 0 0 16px">'+bullets.map(b=>'<li>'+b+'</li>').join('')+'</ul>';
}
$('#analyze').addEventListener('click', analyze);
$('#sample').addEventListener('click', function(){
txt.value = `At the end of the day, our next-generation solution delivers a seamless experience that will move the needle. We generally believe this innovative approach will arguably revolutionize workflows, kind of. It’s probably the best in class.`;
analyze();
});
})();
</script>
</body>
</html>