leaderboards / index.html
ymatari's picture
trust strip only on main page
6612727 verified
Raw
History Blame Contribute Delete
33.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>BenchHub Leaderboards β€” reproducible, apples-to-apples ML benchmarks</title>
<meta name="description" content="Reproducible ML leaderboards β€” LLM (MMLU, HellaSwag, ARC, GSM8K), vision, and audio. Every model scored on the same data with the same metric in a sandbox, not self-reported. Browse standings and submit your model free.">
<meta name="keywords" content="ML leaderboard, model evaluation, reproducible benchmark, MMLU leaderboard, HellaSwag, ARC-Challenge, GSM8K, LLM benchmark, apples-to-apples, object detection, depth estimation, stereo, speech recognition">
<link rel="canonical" href="https://runbenchhub-leaderboards.static.hf.space/">
<meta property="og:type" content="website">
<meta property="og:title" content="BenchHub Leaderboards β€” reproducible, apples-to-apples ML benchmarks">
<meta property="og:description" content="Reproducible LLM, vision & audio leaderboards. Same data, same metric, sandboxed β€” not self-reported. Submit your model free.">
<meta property="og:url" content="https://runbenchhub-leaderboards.static.hf.space/">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="BenchHub Leaderboards β€” reproducible, apples-to-apples ML benchmarks">
<meta name="twitter:description" content="Reproducible LLM, vision & audio leaderboards. Same data, same metric, sandboxed β€” not self-reported. Submit free.">
<meta name="theme-color" content="#7c3aed">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>πŸ†</text></svg>">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebSite","name":"BenchHub Leaderboards","url":"https://runbenchhub.com","description":"Reproducible, apples-to-apples ML benchmarking β€” LLM, vision, and audio leaderboards scored on the same data with the same metric in a sandbox.","keywords":"reproducible ML leaderboard, LLM benchmark, MMLU, HellaSwag, ARC, GSM8K, model evaluation, apples-to-apples","about":[{"@type":"Thing","name":"Large language model evaluation"},{"@type":"Thing","name":"Computer vision benchmarks"},{"@type":"Thing","name":"Reproducible model evaluation"}]}
</script>
<style>
:root{
--violet:#7c3aed; --violet-2:#a78bfa;
--bg:#fcf9f4; --card:#fffdf8; --card-2:#f5efe2; --border:#e8dfc8;
--text:#3a2614; --text-2:#6b5b43; --muted:#9a8c73;
--shadow:0 4px 18px rgba(60,38,20,.08);
--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
body.dark{
--bg:#0f1117; --card:#171a21; --card-2:#1e222b; --border:#2b313c;
--text:#e7e3da; --text-2:#a7adba; --muted:#7c8595;
--shadow:0 4px 22px rgba(0,0,0,.45);
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
line-height:1.45;-webkit-font-smoothing:antialiased;transition:background .2s,color .2s;}
a{color:var(--violet);text-decoration:none}
a:hover{text-decoration:underline}
.wrap{max-width:1140px;margin:0 auto;padding:0 18px 60px}
/* Top bar */
.topbar{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
padding:16px 18px;max-width:1140px;margin:0 auto;}
.brand{font-weight:800;font-size:1.15rem;letter-spacing:-.01em;display:flex;align-items:center;gap:8px}
.brand .dot{color:var(--violet)}
.topbar .spacer{flex:1}
.btn{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--border);
background:var(--card);color:var(--text);border-radius:9px;padding:7px 13px;
font-size:.82rem;font-weight:600;cursor:pointer;transition:all .15s;white-space:nowrap}
.btn:hover{border-color:var(--violet);color:var(--violet);text-decoration:none;transform:translateY(-1px)}
.btn-primary{background:var(--violet);color:#fff;border-color:var(--violet)}
.btn-primary:hover{background:#6d28d9;color:#fff;border-color:#6d28d9}
/* Hero */
.hero{text-align:center;padding:26px 0 8px}
.hero h1{font-size:2rem;margin:.1em 0 .15em;letter-spacing:-.02em}
.hero p{color:var(--text-2);max-width:680px;margin:.2em auto 1.1em;font-size:1.02rem}
.stats{display:flex;justify-content:center;gap:12px;flex-wrap:wrap;margin:10px 0 4px}
.stat{background:var(--card);border:1px solid var(--border);border-top:3px solid var(--violet);
border-radius:12px;padding:12px 20px;min-width:120px;box-shadow:var(--shadow)}
.stat .n{font-size:1.7rem;font-weight:800;font-family:var(--mono);color:var(--violet);line-height:1}
.stat .l{font-size:.72rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin-top:5px}
/* Trust strip */
.trust{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:18px 0 4px}
.trust-item{display:flex;gap:10px;align-items:flex-start;background:var(--card);border:1px solid var(--border);
border-radius:12px;padding:13px 15px;font-size:.84rem;color:var(--text-2);line-height:1.35}
.trust-item span{font-size:1.25rem;line-height:1}
.trust-item b{color:var(--text)}
@media(max-width:720px){.trust{grid-template-columns:1fr}}
/* Controls */
.controls{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:22px 0 10px}
.subcontrols{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:0 0 16px;
padding-left:2px;animation:fade .15s ease}
@keyframes fade{from{opacity:0;transform:translateY(-3px)}to{opacity:1}}
.sublabel{font-size:.76rem;color:var(--muted);font-weight:700;text-transform:uppercase;letter-spacing:.04em}
.subpills .pill{font-size:.76rem;padding:5px 11px;background:var(--card-2)}
.subpills .pill.on{background:var(--violet);color:#fff}
#search{flex:1;min-width:220px;border:1px solid var(--border);background:var(--card);color:var(--text);
border-radius:10px;padding:10px 14px;font-size:.95rem}
#search:focus{outline:none;border-color:var(--violet);box-shadow:0 0 0 3px rgba(124,58,237,.15)}
.pills{display:flex;gap:6px;flex-wrap:wrap}
.pill{border:1px solid var(--border);background:var(--card);color:var(--text-2);border-radius:999px;
padding:6px 13px;font-size:.8rem;font-weight:600;cursor:pointer;transition:all .12s}
.pill:hover{border-color:var(--violet-2)}
.pill.on{background:var(--violet);color:#fff;border-color:var(--violet)}
/* Card grid */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:14px}
.card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:15px 16px;
box-shadow:var(--shadow);cursor:pointer;transition:transform .14s,border-color .14s;
display:flex;flex-direction:column;gap:9px}
.card:hover{transform:translateY(-3px);border-color:var(--violet)}
.card .cat{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;
color:var(--violet);background:rgba(124,58,237,.1);align-self:flex-start;border-radius:6px;padding:2px 8px}
.card h3{margin:0;font-size:1.04rem;letter-spacing:-.01em;word-break:break-word}
.card .lead{font-size:.85rem;color:var(--text-2);display:flex;align-items:center;gap:6px;min-height:1.2em}
.card .lead b{color:var(--text);font-weight:700}
.card .lead .score{font-family:var(--mono);color:#16a34a;font-weight:700}
.card .meta{display:flex;justify-content:space-between;align-items:center;margin-top:auto;padding-top:6px;
border-top:1px solid var(--border);font-size:.78rem;color:var(--muted)}
.card .meta .subs b{color:var(--text);font-family:var(--mono)}
.card .go{color:var(--violet);font-weight:700}
/* Drill-down: area section headers + sub-category cards */
.cat-head{font-size:.78rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-2);
font-weight:800;margin:24px 0 11px;display:flex;align-items:center;gap:8px}
.cat-head:first-child{margin-top:4px}
.cat-head .n{color:var(--muted);font-weight:600}
.grid + .cat-head{margin-top:26px}
.catcard h3{font-size:1.1rem}
#backBar{margin:4px 0 16px}
#backBar .crumb{margin-left:12px;color:var(--text-2);font-weight:700;font-size:.92rem}
#backBar .crumb .area{color:var(--violet)}
/* Board detail */
#board{display:none}
.back{cursor:pointer;color:var(--text-2);font-weight:600;font-size:.88rem;margin-bottom:10px;display:inline-flex;gap:6px}
.back:hover{color:var(--violet)}
.board-head{display:flex;flex-wrap:wrap;align-items:center;gap:10px 16px;margin-bottom:6px}
.board-head h2{margin:0;font-size:1.5rem;letter-spacing:-.01em}
.board-sub{color:var(--text-2);font-size:.9rem;margin:2px 0 16px}
table{border-collapse:collapse;width:100%;font-size:.9rem;background:var(--card);
border:1px solid var(--border);border-radius:12px;overflow:hidden}
thead th{background:var(--card-2);text-align:left;padding:10px 12px;font-size:.74rem;
text-transform:uppercase;letter-spacing:.04em;color:var(--text-2);position:sticky;top:0}
tbody td{padding:9px 12px;border-top:1px solid var(--border);vertical-align:middle}
tbody tr:hover{background:var(--card-2)}
td.num{font-family:var(--mono);text-align:right;font-weight:600}
td.rank{font-family:var(--mono);color:var(--muted);width:42px;text-align:center}
.medal{font-size:1.05em}
/* Model rankings (inline, shown when a sub-category is selected) */
.rk-card{background:var(--card);border:1px solid var(--border);border-radius:14px;
padding:16px 18px;box-shadow:var(--shadow);margin-bottom:18px}
.rk-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:5px}
.rk-head h3{margin:0;font-size:1.18rem;letter-spacing:-.01em}
.rk-meta{color:var(--muted);font-size:.8rem}
.rk-bar{height:8px;border-radius:5px;background:var(--card-2);overflow:hidden;min-width:70px;flex:1}
.rk-bar > i{display:block;height:100%;background:var(--violet)}
/* Clickable per-board chips β†’ open that board's standings */
.rk-chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px}
.rk-bchip{display:inline-flex;align-items:center;gap:5px;font-size:.72rem;line-height:1.1;
padding:2px 8px;border:1px solid var(--border);border-left-width:3px;border-radius:999px;
background:var(--card-2);color:var(--text-2);cursor:pointer;max-width:15rem;
transition:background .12s,color .12s,box-shadow .12s}
.rk-bchip:hover{background:var(--violet);color:#fff;box-shadow:var(--shadow)}
.rk-bchip b{font-family:var(--mono);font-weight:700}
.rk-bchip-name{max-width:11rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Top-3 by default; rk-extra rows reveal when the tbody is expanded. */
tbody:not(.rk-expanded) tr.rk-extra{display:none}
.rk-more{border:1px solid var(--border);background:var(--card);color:var(--violet);
border-radius:999px;padding:6px 16px;font-size:.82rem;font-weight:700;cursor:pointer;transition:all .14s}
.rk-more:hover{border-color:var(--violet);background:var(--violet);color:#fff}
/* Collapsible per-board chip list (default collapsed). */
.rk-boards-d{margin-top:6px}
.rk-boards-d > summary{display:inline-flex;align-items:center;gap:4px;cursor:pointer;list-style:none;
font-size:.74rem;color:var(--violet);width:max-content}
.rk-boards-d > summary::-webkit-details-marker{display:none}
.rk-boards-d > summary::before{content:"β–Έ";font-size:.66rem;transition:transform .12s}
.rk-boards-d[open] > summary::before{transform:rotate(90deg)}
.rk-boards-d > summary:hover{text-decoration:underline}
.rk-boards-d .rk-chips{margin-top:5px}
.cov{font-family:var(--mono);font-size:.78rem;border-radius:6px;padding:2px 8px;border:1px solid;white-space:nowrap}
.cov.full{background:rgba(22,163,74,.12);color:#16a34a;border-color:rgba(22,163,74,.32)}
.cov.part{background:rgba(202,138,4,.13);color:#b45309;border-color:rgba(202,138,4,.32)}
body.dark .cov.part{color:#fbbf24}
.empty{text-align:center;color:var(--muted);padding:48px 0}
footer{text-align:center;color:var(--muted);font-size:.82rem;margin-top:40px;padding-top:20px;border-top:1px solid var(--border)}
.spin{display:inline-block;width:18px;height:18px;border:2px solid var(--border);border-top-color:var(--violet);
border-radius:50%;animation:sp .7s linear infinite;vertical-align:middle}
@keyframes sp{to{transform:rotate(360deg)}}
@media(max-width:560px){.hero h1{font-size:1.55rem}.stat{min-width:90px;padding:10px 14px}}
</style>
</head>
<body>
<div class="topbar">
<div class="brand"><span>πŸ†</span> BenchHub <span class="dot">Leaderboards</span></div>
<div class="spacer"></div>
<button class="btn" id="darkBtn" onclick="toggleDark()">πŸŒ™ Dark</button>
<a class="btn btn-primary" id="ctaTop" target="_blank" rel="noopener">Open BenchHub β†’</a>
</div>
<div class="wrap">
<div class="hero">
<h1>Open, 🍎-to-🍎 ML benchmarks</h1>
<p>Every model scored on the <b>same data</b>, the <b>same metric</b>, in a reproducible sandbox β€”
across LLM, vision, and audio. Browse the standings here; run your model and submit free on BenchHub.</p>
<div class="stats" id="stats"></div>
</div>
<!-- Trust strip: why these numbers are reliable (the conversion hook). -->
<div class="trust" id="trust">
<div class="trust-item"><span>🎯</span><div><b>Same data &amp; metric</b><br>Every model on a board runs the identical eval set and scorer.</div></div>
<div class="trust-item"><span>πŸ“Œ</span><div><b>Pinned protocol</b><br>LLM boards bake one exact prompt β€” zero-shot, exact-match, no per-model tuning.</div></div>
<div class="trust-item"><span>πŸ“¦</span><div><b>Sandboxed, not self-reported</b><br>Predictions are scored server-side in a container β€” reproducible, not paper numbers.</div></div>
</div>
<div class="controls">
<input id="search" type="search" placeholder="πŸ” Search benchmarks by name or domain…" oninput="onSearch(this.value)">
</div>
<!-- Domain filter for the sub-category cards (shown only in the cards view). -->
<div class="subcontrols" id="domainFilter" style="display:none">
<span class="sublabel">Domain</span>
<div class="pills" id="domainPills"></div>
</div>
<!-- Drill-down back link + breadcrumb, shown when inside a sub-category. -->
<div id="backBar" style="display:none"></div>
<!-- Inline meta-ranking: appears when a specific sub-category is selected. -->
<div id="subRanking"></div>
<!-- Holds either sub-category cards (default) or a sub-category's board cards. -->
<div id="grid"><div class="empty"><span class="spin"></span> Loading…</div></div>
<div id="board">
<span class="back" onclick="closeBoard()">← Back</span>
<div class="board-head"><h2 id="bName"></h2></div>
<div class="board-sub" id="bSub"></div>
<div id="bTable"></div>
</div>
<footer>
Read-only mirror of public standings from
<a id="ctaFoot" target="_blank" rel="noopener">runbenchhub.com</a>.
No ground-truth data, no submissions here β€” the interactive explorer, per-sample comparison,
and submission live on BenchHub. <span id="synced"></span>
</footer>
</div>
<script>
const DATA = "https://huggingface.co/datasets/runbenchhub/leaderboards/resolve/main";
const SITE = "https://runbenchhub.com";
const UTM = "utm_source=hf_space&utm_medium=mirror";
const ALL = "All";
let ENTRIES = [], AREA = ALL, SUB = ALL, QUERY = "";
let AGG = []; // sub-category meta-rankings from aggregates.json
function utm(url){ if(!url) return url; return url + (url.includes("?")?"&":"?") + UTM; }
function esc(s){ return String(s==null?"":s).replace(/[&<>"]/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c])); }
function area(cat){ return (cat||"Uncategorized").split("/")[0]; }
function subarea(cat){ const p=(cat||"").split("/"); return p.length>1?p.slice(1).join("/").trim():""; }
function fmtNum(v){ if(v==null||isNaN(v)) return "β€”"; const n=+v; return Number.isInteger(n)?String(n):n.toFixed(4).replace(/0+$/,"").replace(/\.$/,""); }
async function getJSON(path){
const r = await fetch(DATA+path, {cache:"no-cache"});
if(!r.ok) throw new Error(r.status);
return r.json();
}
/* ---------- init ---------- */
(async function init(){
document.getElementById("ctaTop").href = utm(SITE);
document.getElementById("ctaFoot").href = utm(SITE);
if(localStorage.getItem("bh-dark")==="1") document.body.classList.add("dark"), setDarkLabel();
try{
const idx = await getJSON("/index.json");
ENTRIES = (idx.leaderboards||[]).filter(e => (e.n_verified||0) > 0);
// Load the sub-category meta-rankings up front (best-effort) so they're
// ready the moment a sub-category pill is clicked.
try{ const ag = await getJSON("/aggregates.json"); AGG = ag.scopes || []; }catch(_){ AGG = []; }
renderStats(idx);
applyNav(parseHash()); // restore view from the URL hash (deep link / refresh)
replaceNav(); // seed the history entry for this view
const g = idx.generated_at;
if(g) document.getElementById("synced").textContent = "Last synced "+new Date(g).toLocaleDateString(undefined,{year:"numeric",month:"short",day:"numeric"})+".";
}catch(e){
document.getElementById("grid").innerHTML = '<div class="empty">Couldn’t load standings right now. <a href="'+utm(SITE)+'" target="_blank" rel="noopener">Open BenchHub β†’</a></div>';
}
})();
function renderStats(idx){
const subs = ENTRIES.reduce((a,e)=>a+(e.n_verified||0),0);
// Distinct sub-categories (full "Area/Sub" category strings) β€” reflects the
// breadth of the catalog better than the handful of top-level domains.
const subcats = new Set(ENTRIES.map(e=>e.category||"Uncategorized")).size;
const el = document.getElementById("stats");
const cards = [["Benchmarks",ENTRIES.length],["Submissions",subs],["Sub-categories",subcats]];
el.innerHTML = cards.map(c=>`<div class="stat"><div class="n" data-to="${c[1]}">0</div><div class="l">${c[0]}</div></div>`).join("");
el.querySelectorAll(".n").forEach(countUp);
}
function countUp(node){
const to=+node.dataset.to||0, dur=900, t0=performance.now();
function step(t){ const p=Math.min(1,(t-t0)/dur); node.textContent=Math.round(to*(1-Math.pow(1-p,3))); if(p<1)requestAnimationFrame(step); }
requestAnimationFrame(step);
}
const jsstr = s => String(s).replace(/\\/g,"\\\\").replace(/'/g,"\\'");
// Two-level browse: sub-category cards (default) -> a sub-category's boards.
// AREA/SUB === ALL means "browsing categories"; both set means "inside a sub".
let BOARD = null; // open board id, or null
// --- History API: browser Back/Forward mirror the in-app drill-down ---
function hashFor(){
if(BOARD!=null) return "#b/"+BOARD;
if(QUERY) return "#q/"+encodeURIComponent(QUERY);
if(AREA!==ALL && SUB!==ALL) return "#c/"+encodeURIComponent(AREA)+"/"+encodeURIComponent(SUB);
if(AREA!==ALL) return "#d/"+encodeURIComponent(AREA);
return "#";
}
function navState(){ return {area:AREA, sub:SUB, query:QUERY, board:BOARD}; }
function pushNav(){ try{ history.pushState(navState(), "", hashFor()); }catch(e){} }
function replaceNav(){ try{ history.replaceState(navState(), "", hashFor()); }catch(e){} }
function parseHash(){
const h=decodeURIComponent(location.hash||""); let m;
if(m=h.match(/^#b\/(\d+)/)) return {board:+m[1]};
if(m=h.match(/^#q\/(.+)/)) return {query:m[1].toLowerCase()};
if(m=h.match(/^#c\/([^/]+)\/(.+)/)) return {area:m[1], sub:m[2]};
if(m=h.match(/^#d\/(.+)/)) return {area:m[1]};
return {};
}
function applyNav(s){ // set state from a popped/parsed entry; no new push
s=s||{};
AREA=s.area||ALL; SUB=s.sub||ALL; QUERY=s.query||""; BOARD=(s.board!=null?s.board:null);
const i=document.getElementById("search"); if(i) i.value=QUERY;
if(BOARD!=null) openBoard(BOARD, true); else render();
}
window.addEventListener("popstate", function(e){ applyNav(e.state || parseHash()); window.scrollTo({top:0}); });
function onSearch(v){ const had=!!QUERY; QUERY=(v||"").trim().toLowerCase(); BOARD=null; render(); if(QUERY&&!had) pushNav(); else replaceNav(); }
function enterSub(a,s){ AREA=a; SUB=s; QUERY=""; BOARD=null; const i=document.getElementById("search"); if(i) i.value=""; pushNav(); render(); window.scrollTo({top:0,behavior:"smooth"}); }
function backToCats(){ history.back(); } // in-app back == browser back
// Master view dispatcher.
function render(){
const bb=document.getElementById("backBar"), sr=document.getElementById("subRanking"),
df=document.getElementById("domainFilter"), tr=document.getElementById("trust");
document.getElementById("board").style.display="none";
document.querySelector(".controls").style.display="";
document.getElementById("grid").style.display="";
if(QUERY){ // search: flat board cards across all
tr.style.display="none"; df.style.display="none"; bb.style.display="none"; sr.innerHTML=""; renderBoardCards(searchList());
} else if(AREA!==ALL && SUB!==ALL){ // inside a sub-category
tr.style.display="none"; df.style.display="none"; bb.style.display="";
bb.innerHTML=`<span class="back" onclick="backToCats()">← All categories</span>`+
`<span class="crumb"><span class="area">${esc(AREA)}</span> Β· ${esc(SUB)}</span>`;
renderSubRanking();
renderBoardCards(subList());
} else { // main page: sub-category cards (+ domain filter + trust strip)
bb.style.display="none"; sr.innerHTML="";
tr.style.display=""; df.style.display="flex"; renderDomainPills(); renderCatCards();
}
}
// Domain (top-level area) filter for the cards view β€” narrows which
// sub-category cards show. AREA===ALL shows every domain.
function renderDomainPills(){
const areas=catGroups().map(g=>g[0]); // ordered by board count desc
document.getElementById("domainPills").innerHTML =
[ALL,...areas].map(a=>`<span class="pill ${a===AREA?'on':''}" onclick="setDomain('${jsstr(a)}')">${esc(a)}</span>`).join("");
}
function setDomain(a){ AREA=a; SUB=ALL; QUERY=""; BOARD=null; const i=document.getElementById("search"); if(i) i.value=""; pushNav(); render(); }
function searchList(){
return ENTRIES.filter(e=>(e.name+" "+(e.category||"")).toLowerCase().includes(QUERY))
.sort((a,b)=>(b.n_verified||0)-(a.n_verified||0));
}
function subList(){
return ENTRIES.filter(e=>area(e.category)===AREA && (subarea(e.category)||"General")===SUB)
.sort((a,b)=>(b.n_verified||0)-(a.n_verified||0));
}
// area -> [[sub, count], ...] desc by count, for the default card view.
function catGroups(){
const m={};
ENTRIES.forEach(e=>{ const a=area(e.category), s=subarea(e.category)||"General";
(m[a]=m[a]||{}); m[a][s]=(m[a][s]||0)+1; });
return Object.keys(m).sort((x,y)=>{
const cx=Object.values(m[x]).reduce((p,c)=>p+c,0), cy=Object.values(m[y]).reduce((p,c)=>p+c,0);
return cy-cx || x.localeCompare(y);
}).map(a=>[a, Object.entries(m[a]).sort((p,q)=>q[1]-p[1])]);
}
function renderCatCards(){
let groups=catGroups();
if(AREA!==ALL) groups=groups.filter(([a])=>a===AREA); // domain filter
if(!groups.length){ document.getElementById("grid").innerHTML='<div class="empty">No benchmarks yet.</div>'; return; }
document.getElementById("grid").innerHTML = groups.map(([a,subs])=>{
const total=subs.reduce((p,[,c])=>p+c,0);
const cards=subs.map(([s,c])=>
`<div class="card catcard" onclick="enterSub('${jsstr(a)}','${jsstr(s)}')">
<span class="cat">${esc(a)}</span>
<h3>${esc(s)}</h3>
<div class="meta"><span class="subs"><b>${c}</b> board${c===1?"":"s"}</span><span class="go">Browse β†’</span></div>
</div>`).join("");
return `<div class="cat-head">${esc(a)} <span class="n">${total}</span></div><div class="grid">${cards}</div>`;
}).join("");
}
function renderBoardCards(list){
const wrap=document.getElementById("grid");
if(!list.length){ wrap.innerHTML='<div class="empty">No benchmarks match.</div>'; return; }
wrap.innerHTML = '<div class="grid">'+list.map(e=>{
const sa = subarea(e.category);
const top = e.top;
const lead = top && top.name
? `πŸ₯‡ <b>${esc(top.name)}</b>${top.score!=null?` <span class="score">${fmtNum(top.score)}</span>`:""}`
: `<span style="color:var(--muted)">${e.n_verified} ranked model${e.n_verified===1?"":"s"}</span>`;
return `<div class="card" onclick="openBoard(${e.id})">
<span class="cat">${esc(area(e.category))}${sa?" Β· "+esc(sa):""}</span>
<h3>${esc(e.name)}</h3>
<div class="lead">${lead}</div>
<div class="meta">
<span class="subs"><b>${e.n_verified}</b> submission${e.n_verified===1?"":"s"}</span>
<span class="go">Standings β†’</span>
</div>
</div>`;
}).join("")+'</div>';
}
// Sub-category meta-ranking, shown inline above the board cards inside a sub.
function renderSubRanking(){
const box=document.getElementById("subRanking");
if(AREA===ALL || SUB===ALL){ box.innerHTML=""; return; }
const scope=(AGG||[]).find(s=>s.scope===AREA+"/"+SUB);
box.innerHTML = scope ? renderScope(scope) : "";
}
/* ---------- board detail ---------- */
function aggRanks(verified, cols){
const n=verified.length; if(!n||!cols.length) return {};
const tot=Array(n).fill(0), cnt=Array(n).fill(0);
for(const c of cols){
const mid=String(c.metric_id), higher=(c.sort_direction||"higher_is_better")!=="lower_is_better";
const scored=[], missing=[];
verified.forEach((r,i)=>{ const v=(r.scores||{})[mid]; (typeof v==="number"?scored:missing).push([i,v]); });
if(!scored.length) continue;
scored.sort((a,b)=>higher?b[1]-a[1]:a[1]-b[1]);
let k=0;
while(k<scored.length){ let j=k; while(j+1<scored.length && scored[j+1][1]===scored[k][1]) j++;
const avg=(k+j)/2+1; for(let t=k;t<=j;t++){ tot[scored[t][0]]+=avg; cnt[scored[t][0]]++; } k=j+1; }
for(const [i] of missing){ tot[i]+=n; cnt[i]++; }
}
const out={}; for(let i=0;i<n;i++) if(cnt[i]) out[i]=tot[i]/cnt[i];
return out;
}
function greenStyle(v, lo, hi, higher){
if(v==null||isNaN(v)) return "";
const rng=(hi-lo)||1; let norm=(v-lo)/rng; if(!higher) norm=1-norm;
return `background-color:hsl(120,68%,${(90-norm*47).toFixed(0)}%);color:#0b3d0b;`;
}
async function openBoard(id, fromPop){
BOARD=id; if(!fromPop) pushNav();
document.getElementById("trust").style.display="none";
document.getElementById("grid").style.display="none";
document.querySelector(".controls").style.display="none";
document.getElementById("backBar").style.display="none";
document.getElementById("subRanking").innerHTML="";
const b=document.getElementById("board"); b.style.display="block";
document.getElementById("bName").textContent="Loading…";
document.getElementById("bSub").innerHTML="";
document.getElementById("bTable").innerHTML='<div class="empty"><span class="spin"></span></div>';
window.scrollTo({top:0,behavior:"smooth"});
let d; try{ d=await getJSON("/leaderboards/"+id+".json"); }
catch(e){ document.getElementById("bTable").innerHTML='<div class="empty">Couldn’t load this board.</div>'; return; }
const cols=d.columns||[], verified=d.verified||[];
document.getElementById("bName").textContent=d.name||"";
const view=utm(d.url||`${SITE}/leaderboard/${id}`), submit=utm(d.submit_url||`${SITE}/leaderboard/${id}`);
document.getElementById("bSub").innerHTML =
`<span style="color:var(--violet);font-weight:700">${esc(d.category||"Uncategorized")}</span> Β· `+
`${verified.length} submission${verified.length===1?"":"s"} &nbsp; `+
`<a class="btn btn-primary" href="${submit}" target="_blank" rel="noopener" style="padding:5px 12px">πŸš€ Submit your model</a> `+
`<a class="btn" href="${view}" target="_blank" rel="noopener" style="padding:5px 12px">Full board β†—</a>`;
if(!verified.length){ document.getElementById("bTable").innerHTML='<div class="empty">No ranked submissions yet.</div>'; return; }
const multi=cols.length>1;
const agg=aggRanks(verified,cols);
const order=verified.map((_,i)=>i).sort((a,b)=>(agg[a]??1e9)-(agg[b]??1e9));
// column ranges for the heatmap
const ranges=cols.map(c=>{ const mid=String(c.metric_id);
const nums=verified.map(r=>(r.scores||{})[mid]).filter(v=>typeof v==="number");
return {lo:Math.min(...nums), hi:Math.max(...nums), higher:(c.sort_direction||"higher_is_better")!=="lower_is_better"}; });
const aggNums=Object.values(agg); const aggLo=Math.min(...aggNums), aggHi=Math.max(...aggNums);
let head="<tr><th>#</th><th>Submission</th><th>Author</th>";
if(multi) head+="<th>Agg. rank</th>";
head+=cols.map(c=>`<th style="text-align:right">${esc(c.label)}</th>`).join("")+"</tr>";
const medals=["πŸ₯‡","πŸ₯ˆ","πŸ₯‰"];
let body="";
order.forEach((i,pos)=>{
const r=verified[i], rk=pos+1;
const name=esc(r.name||"");
const sub=r.link?`<a href="${utm(esc(r.link))}" target="_blank" rel="noopener">${name}</a>`:name;
const author=r.author_url?`<a href="${esc(r.author_url)}" target="_blank" rel="noopener">${esc(r.author||"")}</a>`:esc(r.author||"");
let row=`<tr><td class="rank">${pos<3?`<span class="medal">${medals[pos]}</span>`:rk}</td>`+
`<td>${sub}</td><td style="color:var(--text-2)">${author||"β€”"}</td>`;
if(multi){ const a=agg[i]; row+=`<td class="num" style="${greenStyle(a,aggLo,aggHi,false)}">${a!=null?a.toFixed(2):"β€”"}</td>`; }
cols.forEach((c,ci)=>{ const v=(r.scores||{})[String(c.metric_id)];
row+=`<td class="num" style="${greenStyle(typeof v==="number"?v:null,ranges[ci].lo,ranges[ci].hi,ranges[ci].higher)}">${fmtNum(v)}</td>`; });
body+=row+"</tr>";
});
document.getElementById("bTable").innerHTML=`<table>${head}${body}</table>`;
}
function closeBoard(){ history.back(); } // in-app back == browser back (popstate restores the view)
/* ---------- model rankings ---------- */
// 0..1 β†’ violet ramp, matching the site's hsl(258,70%,...) per-board bars
function miniColor(nv){ return `hsl(258,70%,${Math.round(88 - nv*48)}%)`; }
function renderScope(s){
const medals=["πŸ₯‡","πŸ₯ˆ","πŸ₯‰"];
const list=(s.models||[]).slice(0,50);
const rows = list.map((m,i)=>{
const rk=i+1;
const name = m.link ? `<a href="${utm(esc(m.link))}" target="_blank" rel="noopener">${esc(m.model)}</a>` : esc(m.model);
// Clickable per-board chips: each opens that board's standings, tinted by
// the model's normalized score there.
const chips = Object.entries(m.per_board||{}).map(([bn,info])=>{
const nv=+info.norm;
return `<span class="rk-bchip" title="See this model on β€œ${esc(bn)}” β€” normalized ${nv.toFixed(2)}"`+
` style="border-left-color:${miniColor(nv)}" onclick="event.stopPropagation();openBoard(${info.lb_id})">`+
`<span class="rk-bchip-name">${esc(bn)}</span><b>${nv.toFixed(2)}</b></span>`;
}).join("");
const full = m.coverage===s.n_boards;
// Per-board chips collapsed by default (native <details>).
const boards = `<details class="rk-boards-d"><summary>${m.coverage} board${m.coverage===1?"":"s"}</summary><div class="rk-chips">${chips}</div></details>`;
return `<tr class="${i>=3?"rk-extra":""}">
<td class="rank">${rk<=3?`<span class="medal">${medals[rk-1]}</span>`:rk}</td>
<td><div style="font-weight:600;word-break:break-word">${name}</div>${boards}</td>
<td><div style="display:flex;align-items:center;gap:8px">
<div class="rk-bar"><i style="width:${Math.round((+m.score)*100)}%"></i></div>
<span class="num" style="font-weight:700">${(+m.score).toFixed(3)}</span>
</div></td>
<td style="text-align:center"><span class="cov ${full?"full":"part"}">${m.coverage}/${s.n_boards}</span></td>
</tr>`;
}).join("");
const shown=list.length;
// Top 3 by default; "Show all" reveals the rest (rk-extra rows).
const toggle = shown>3 ? `<div style="text-align:center;margin-top:10px"><button class="rk-more" data-more="Show all ${shown} models" data-less="Show top 3" onclick="rkToggle(this)">Show all ${shown} models</button></div>` : "";
const more = s.n_models>50 ? `<div class="rk-meta" style="margin-top:7px;text-align:center">Top 50 of ${s.n_models} models.</div>` : "";
return `<div class="rk-card">
<div class="rk-head">
<h3>πŸ† Model ranking</h3>
<span class="rk-meta">Β· combined across ${s.n_boards} boards Β· ${s.n_models} models</span>
</div>
<table><thead><tr><th>#</th><th>Model</th><th>Score</th><th style="text-align:center">Coverage</th></tr></thead>
<tbody>${rows}</tbody></table>
${toggle}${more}
</div>`;
}
// Expand/collapse the ranking table (top 3 ⇄ all).
function rkToggle(btn){
const tb=btn.closest(".rk-card").querySelector("tbody");
const exp=tb.classList.toggle("rk-expanded");
btn.textContent = exp ? btn.dataset.less : btn.dataset.more;
}
/* ---------- dark mode ---------- */
function setDarkLabel(){ document.getElementById("darkBtn").textContent=document.body.classList.contains("dark")?"β˜€οΈ Light":"πŸŒ™ Dark"; }
function toggleDark(){ document.body.classList.toggle("dark"); localStorage.setItem("bh-dark",document.body.classList.contains("dark")?"1":"0"); setDarkLabel(); }
</script>
</body>
</html>