Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Bench Labs Leaderboard</title> | |
| <meta name="description" content="Model performance across Bench Labs' benchmark suite — dual-mode 7-2026 tiers, legacy 6-2026 runs, and text-to-image FID scores."> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Newsreader:ital,opsz,wght@0,6..72,400;1,6..72,300;1,6..72,400&display=swap" rel="stylesheet"> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| fontFamily: { | |
| sans: ['Inter', 'sans-serif'], | |
| serif: ['Newsreader', 'serif'], | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <link rel="stylesheet" href="style.css"> | |
| </head> | |
| <body class="antialiased min-h-screen overflow-y-auto selection:bg-[rgba(124,156,255,0.35)]"> | |
| <div class="space-bg"></div> | |
| <canvas class="stars" id="stars"></canvas> | |
| <div class="relative z-10 min-h-screen flex flex-col items-center px-6 py-14 md:py-16"> | |
| <!-- Logo --> | |
| <img src="benchlabs.svg" alt="Bench-labs" class="h-14 md:h-16 w-auto mb-6 fade d1" | |
| style="filter: drop-shadow(0 0 18px rgba(124,156,255,0.35));" /> | |
| <!-- Hero --> | |
| <header class="hero text-center max-w-3xl w-full fade d2"> | |
| <h1 class="font-serif italic text-[2.2rem] md:text-[2.7rem] leading-[0.95] tracking-tight">Leaderboard</h1> | |
| <p class="subtitle mt-3 text-sm md:text-[14.5px] leading-6 font-light max-w-[56ch] mx-auto"> | |
| <span id="rotating-headline" class="rotating-headline text-[var(--ink)] font-normal">Every evaluated model, every benchmark, one table.</span> | |
| </p> | |
| </header> | |
| <!-- Stats --> | |
| <section class="stat-row max-w-5xl w-full mt-8 fade d3" id="stat-row" aria-label="Summary statistics"></section> | |
| <!-- Controls --> | |
| <section class="controls max-w-5xl w-full fade d3"> | |
| <div class="chip-row" id="gen-chips" role="tablist" aria-label="Benchmark generation"></div> | |
| <div class="controls-right"> | |
| <label class="search-pill"> | |
| <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="11" cy="11" r="6"/><line x1="20" y1="20" x2="15.5" y2="15.5"/></svg> | |
| <input type="search" id="model-search" placeholder="Search models or orgs…" aria-label="Search models"> | |
| </label> | |
| <div class="sort-pill" id="sort-pill"> | |
| <span class="sort-label">Sort</span> | |
| <button type="button" class="sort-trigger" id="sort-trigger" aria-haspopup="listbox" aria-expanded="false" aria-labelledby="sort-trigger-label"> | |
| <span id="sort-trigger-label">Avg ↓</span> | |
| <svg class="sort-chevron" width="10" height="6" viewBox="0 0 10 6" fill="none"><path d="M1 1L5 5L9 1" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg> | |
| </button> | |
| <ul class="sort-menu" id="sort-menu" role="listbox" aria-labelledby="sort-trigger-label" tabindex="-1" hidden> | |
| <li role="option" data-value="avg-desc" aria-selected="true" class="selected">Avg ↓</li> | |
| <li role="option" data-value="avg-asc" aria-selected="false">Avg ↑</li> | |
| <li role="option" data-value="params-asc" aria-selected="false">Params ↑</li> | |
| <li role="option" data-value="params-desc" aria-selected="false">Params ↓</li> | |
| <li role="option" data-value="name-asc" aria-selected="false">Name A–Z</li> | |
| </ul> | |
| <select id="sort-select" aria-hidden="true" tabindex="-1"> | |
| <option value="avg-desc" selected>Avg ↓</option> | |
| <option value="avg-asc">Avg ↑</option> | |
| <option value="params-asc">Params ↑</option> | |
| <option value="params-desc">Params ↓</option> | |
| <option value="name-asc">Name A–Z</option> | |
| </select> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Table card --> | |
| <section class="table-card max-w-5xl w-full fade d4"> | |
| <div class="table-scroll"> | |
| <table id="lb"> | |
| <thead id="lb-head"></thead> | |
| <tbody id="lb-body"></tbody> | |
| </table> | |
| </div> | |
| <div id="model-cards" aria-label="Models (mobile view)"></div> | |
| <div id="empty-state" hidden> | |
| <p class="empty-title">No models evaluated on this generation yet.</p> | |
| <p class="empty-sub">The 7-2026 tiers are brand new — run | |
| <code>python script.py --model <your-model></code> and open a PR with the | |
| <code>leaderboard.json</code> it prints. Or view the | |
| <button type="button" class="linklike" id="show-legacy">6-2026 runs</button>.</p> | |
| </div> | |
| </section> | |
| <!-- Text-to-image mini leaderboard (independent track: FID / MS-COCO) --> | |
| <section id="t2i-section" class="max-w-5xl w-full fade d4" hidden> | |
| <div class="section-heading"> | |
| <h2>Text-to-image</h2> | |
| <span class="section-note">FID on MS-COCO — lower is better</span> | |
| </div> | |
| <div class="table-card"> | |
| <div class="table-scroll"> | |
| <table id="t2i-table"> | |
| <thead id="t2i-head"></thead> | |
| <tbody id="t2i-body"></tbody> | |
| </table> | |
| </div> | |
| <div id="t2i-cards" aria-label="Text-to-image models (mobile view)"></div> | |
| <div id="t2i-empty" hidden> | |
| <p>No text-to-image models evaluated yet.</p> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Howto --> | |
| <section class="howto max-w-5xl w-full fade d5"> | |
| <details id="howto-details"> | |
| <summary>Entry schema & how to submit</summary> | |
| <div class="howto-content"> | |
| <div class="howto-content-inner"> | |
| <p>Run the universal script — it fetches the live leaderboard and merges your run into it, writing an upload-ready <code>models.json</code> next to the results:</p> | |
| <pre><code>python script.py --model your-org/your-model | |
| # then upload benchlabs_results/<model>/models.json to this Space (PR welcome). | |
| # Same model id: only the tiers you just ran are replaced; everything else kept. | |
| # 7-2026 runs report both modes: | |
| # metrics.generative exact_match · hybrid_score (alias-aware, per-item routing) | |
| # metrics.loglikelihood acc · acc_norm · soft_score · soft_score_norm | |
| # model_revision + script_sha256 pin exactly what was evaluated. | |
| # | |
| # Text-to-image entries (FID / MS-COCO) live in a separate top-level | |
| # "t2i_models" array in models.json — see add_t2i_schema.py for the entry shape.</code></pre> | |
| </div> | |
| </div> | |
| </details> | |
| </section> | |
| <!-- Footer --> | |
| <footer class="foot max-w-5xl w-full fade d6"> | |
| <div class="section-divider mb-6"><div class="line"></div><span class="text-[10px] tracking-widest uppercase text-[var(--muted-2)]">bench-labs</span><div class="line"></div></div> | |
| <p>Bench Labs — simple, reliable, open sourced. | |
| Data: <a href="models.json">models.json</a> · | |
| Datasets: <a href="https://huggingface.co/bench-labs" target="_blank" rel="noopener">huggingface.co/bench-labs</a> | |
| </p> | |
| </footer> | |
| </div> | |
| <!-- Starfield + rotating headline scripts (same architecture as Members) --> | |
| <script> | |
| (()=>{ | |
| const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; | |
| const isMobile = window.matchMedia("(max-width: 767px)").matches || navigator.userAgentData?.mobile === true || /Android|iPhone|iPad|iPod/i.test(navigator.userAgent); | |
| const canvas = document.getElementById("stars"); | |
| if (!canvas) return; | |
| const ctx = canvas.getContext("2d"); | |
| let dpr = Math.min(window.devicePixelRatio || 1, 2); | |
| let W = 0, H = 0; | |
| function resize() { | |
| W = window.innerWidth; H = window.innerHeight; | |
| canvas.width = Math.floor(W * dpr); | |
| canvas.height = Math.floor(H * dpr); | |
| canvas.style.width = W + "px"; | |
| canvas.style.height = H + "px"; | |
| ctx.setTransform(dpr, 0, 0, dpr, 0, 0); | |
| } | |
| resize(); | |
| let resizeTimer; | |
| window.addEventListener("resize", ()=>{ | |
| clearTimeout(resizeTimer); | |
| resizeTimer = setTimeout(resize, 150); | |
| }); | |
| // ---------- Background stars: tiny radius, slow drift, subtle twinkle ---------- | |
| const STAR_COUNT = isMobile ? 90 : 190; | |
| const stars = []; | |
| for (let i=0;i<STAR_COUNT;i++) { | |
| const big = Math.random() < 0.12; | |
| stars.push({ | |
| x: Math.random()*W, | |
| y: Math.random()*H, | |
| r: big ? (0.8 + Math.random()*0.2) : (0.5 + Math.random()*0.5), // 0.5px - 1px radius | |
| baseOp: 0.25 + Math.random()*0.35, | |
| twinkleAmp: 0.25 + Math.random()*0.45, | |
| twinkleSpeed: 0.4 + Math.random()*0.8, // rad/sec-ish | |
| phase: Math.random()*Math.PI*2, | |
| vx: (Math.random()-0.5) * 0.012, // slow drift, px/frame-ish (scaled by dt) | |
| vy: (Math.random()-0.5) * 0.012 + 0.004, // gentle downward bias | |
| }); | |
| } | |
| // ---------- Shooting stars: dense particle trail instead of a single dash ---------- | |
| function spawnShootingStar(delay=0) { | |
| const angle = (18 + Math.random()*26) * (Math.PI/180); // 18°-44° downward-right | |
| const speed = 620 + Math.random()*420; // px/sec, varied | |
| const startX = -0.15*W - Math.random()*0.1*W; | |
| const startY = Math.random()*H*0.55; | |
| return { | |
| x: startX, y: startY, | |
| vx: Math.cos(angle)*speed, | |
| vy: Math.sin(angle)*speed, | |
| life: 0, | |
| maxLife: 0.9 + Math.random()*0.5, // seconds visible | |
| delay, | |
| len: 70 + Math.random()*90, // trail length in px | |
| thickness: 1 + Math.random()*1.1, | |
| trail: [], // recent positions for dense particle trail | |
| active: false, | |
| done: false, | |
| }; | |
| } | |
| const shootingStars = []; | |
| if (!isMobile && !prefersReducedMotion) { | |
| const SHOOTER_COUNT = 3; | |
| for (let i=0;i<SHOOTER_COUNT;i++) { | |
| shootingStars.push(spawnShootingStar(i*3.5 + Math.random()*4)); | |
| } | |
| } | |
| let lastTime = performance.now(); | |
| let elapsed = 0; | |
| function drawStars(dt) { | |
| for (const s of stars) { | |
| s.x += s.vx * dt * 60; | |
| s.y += s.vy * dt * 60; | |
| // wrap around edges so drift is seamless/continuous | |
| if (s.x < -2) s.x = W + 2; else if (s.x > W + 2) s.x = -2; | |
| if (s.y < -2) s.y = H + 2; else if (s.y > H + 2) s.y = -2; | |
| const tw = prefersReducedMotion ? 0 : Math.sin(elapsed*s.twinkleSpeed + s.phase) * s.twinkleAmp; | |
| const op = Math.max(0.04, Math.min(1, s.baseOp + tw)); | |
| ctx.beginPath(); | |
| ctx.arc(s.x, s.y, s.r, 0, Math.PI*2); | |
| ctx.fillStyle = `rgba(255,255,255,${op.toFixed(3)})`; | |
| ctx.fill(); | |
| } | |
| } | |
| function drawShootingStars(dt) { | |
| for (const sh of shootingStars) { | |
| if (sh.done) continue; | |
| if (!sh.active) { | |
| sh.delay -= dt; | |
| if (sh.delay > 0) continue; | |
| sh.active = true; | |
| } | |
| sh.life += dt; | |
| sh.x += sh.vx * dt; | |
| sh.y += sh.vy * dt; | |
| // push a dense trail point every frame — no gaps between renders | |
| sh.trail.push({x: sh.x, y: sh.y, t: sh.life}); | |
| // trim trail to the visual length window | |
| const speedMag = Math.hypot(sh.vx, sh.vy); | |
| const trailDuration = sh.len / speedMag; | |
| while (sh.trail.length && (sh.life - sh.trail[0].t) > trailDuration) sh.trail.shift(); | |
| // fade in over first 8% of life, fade out over last 35% | |
| const lifeRatio = sh.life / sh.maxLife; | |
| let fade = 1; | |
| if (lifeRatio < 0.08) fade = lifeRatio/0.08; | |
| else if (lifeRatio > 0.65) fade = Math.max(0, 1 - (lifeRatio-0.65)/0.35); | |
| if (sh.trail.length > 1 && fade > 0.01) { | |
| for (let i=1;i<sh.trail.length;i++) { | |
| const p0 = sh.trail[i-1], p1 = sh.trail[i]; | |
| const segAge = (sh.life - p1.t) / trailDuration; // 0 (new/head) -> 1 (old/tail) | |
| const segOp = Math.max(0, (1 - segAge)) * fade * 0.85; | |
| if (segOp <= 0.01) continue; | |
| ctx.beginPath(); | |
| ctx.moveTo(p0.x, p0.y); | |
| ctx.lineTo(p1.x, p1.y); | |
| ctx.strokeStyle = `rgba(255,255,255,${segOp.toFixed(3)})`; | |
| ctx.lineWidth = sh.thickness * (1 - segAge*0.6); | |
| ctx.lineCap = "round"; | |
| ctx.stroke(); | |
| } | |
| // bright head | |
| const head = sh.trail[sh.trail.length-1]; | |
| ctx.beginPath(); | |
| ctx.arc(head.x, head.y, sh.thickness*0.9, 0, Math.PI*2); | |
| ctx.fillStyle = `rgba(255,255,255,${(fade*0.95).toFixed(3)})`; | |
| ctx.fill(); | |
| } | |
| // respawn once fully done (off-screen or life exceeded) with fresh randomized params | |
| if (sh.life > sh.maxLife || sh.x > W*1.15 || sh.y > H*1.15) { | |
| const fresh = spawnShootingStar(2 + Math.random()*6); | |
| Object.assign(sh, fresh); | |
| } | |
| } | |
| } | |
| function frame(now) { | |
| const dt = Math.min((now - lastTime) / 1000, 0.05); // clamp for tab-switch jumps | |
| lastTime = now; | |
| elapsed += dt; | |
| ctx.clearRect(0, 0, W, H); | |
| drawStars(dt); | |
| if (!isMobile) drawShootingStars(dt); | |
| if (running) requestAnimationFrame(frame); | |
| } | |
| let running = true; | |
| // adaptive perf ladder: drop shooting stars, then thin background stars, if fps sags | |
| if (!prefersReducedMotion) { | |
| let cuts = 0; | |
| const steps = [ | |
| ()=>{ shootingStars.length = 0; }, | |
| ()=>{ for (let i=stars.length-1; i>=0; i-=2) stars.splice(i,1); } | |
| ]; | |
| let frames=0, winStart=0, low=0; | |
| const TH=30, SAMPLE=1000, PAT=2; | |
| const origFrame = frame; | |
| let frameCount=0; | |
| const perfTick = () => { | |
| frameCount++; | |
| const now = performance.now(); | |
| const el = now - winStart; | |
| if (el >= SAMPLE) { | |
| const fps = (frameCount*1000)/el; | |
| frameCount = 0; winStart = now; | |
| if (fps < TH) { if (++low >= PAT && cuts < steps.length) { low=0; steps[cuts](); cuts++; } } else low = 0; | |
| } | |
| if (cuts < steps.length && running) requestAnimationFrame(perfTick); | |
| }; | |
| setTimeout(()=>{ winStart = performance.now(); requestAnimationFrame(perfTick); }, 1500); | |
| } | |
| requestAnimationFrame(frame); | |
| })(); | |
| </script> | |
| <script> | |
| // Smooth open/close for the "Entry schema" <details> block. | |
| // Native <details> can't transition display:none<->block, so we intercept | |
| // the toggle, keep the element open during the close animation, and drive | |
| // max-height/opacity in JS based on the content's real scrollHeight. | |
| (()=>{ | |
| const details = document.getElementById("howto-details"); | |
| if (!details) return; | |
| const summary = details.querySelector("summary"); | |
| const content = details.querySelector(".howto-content"); | |
| if (!summary || !content) return; | |
| const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches; | |
| let animating = false; | |
| function openIt() { | |
| details.open = true; | |
| const target = content.scrollHeight; | |
| content.style.maxHeight = target + "px"; | |
| animating = true; | |
| content.addEventListener("transitionend", function onEnd(e){ | |
| if (e.propertyName !== "max-height") return; | |
| content.removeEventListener("transitionend", onEnd); | |
| content.style.maxHeight = "none"; // allow content reflow (e.g. resize) while open | |
| animating = false; | |
| }); | |
| } | |
| function closeIt() { | |
| // pin current height first so the transition has a start point | |
| content.style.maxHeight = content.scrollHeight + "px"; | |
| requestAnimationFrame(()=>{ | |
| requestAnimationFrame(()=>{ content.style.maxHeight = "0px"; }); | |
| }); | |
| animating = true; | |
| content.addEventListener("transitionend", function onEnd(e){ | |
| if (e.propertyName !== "max-height") return; | |
| content.removeEventListener("transitionend", onEnd); | |
| details.open = false; | |
| animating = false; | |
| }); | |
| } | |
| summary.addEventListener("click", (e) => { | |
| if (reduce) return; // let native behavior handle it | |
| e.preventDefault(); | |
| if (animating) return; | |
| if (details.open) closeIt(); else openIt(); | |
| }); | |
| })(); | |
| </script> | |
| <script> | |
| // Custom sort dropdown — drives the hidden real <select> so any existing | |
| // script.js listener on #sort-select 'change' keeps working untouched. | |
| (()=>{ | |
| const pill = document.getElementById("sort-pill"); | |
| const trigger = document.getElementById("sort-trigger"); | |
| const label = document.getElementById("sort-trigger-label"); | |
| const menu = document.getElementById("sort-menu"); | |
| const realSelect = document.getElementById("sort-select"); | |
| if (!pill || !trigger || !menu || !realSelect) return; | |
| const items = Array.from(menu.querySelectorAll("li")); | |
| function closeMenu() { | |
| menu.classList.remove("show"); | |
| pill.classList.remove("open"); | |
| trigger.setAttribute("aria-expanded", "false"); | |
| setTimeout(()=>{ if (!menu.classList.contains("show")) menu.hidden = true; }, 150); | |
| } | |
| function openMenu() { | |
| menu.hidden = false; | |
| requestAnimationFrame(()=> menu.classList.add("show")); | |
| pill.classList.add("open"); | |
| trigger.setAttribute("aria-expanded", "true"); | |
| const current = items.find(i => i.classList.contains("selected")); | |
| (current || items[0]).focus(); | |
| } | |
| function selectItem(item) { | |
| items.forEach(i => { i.classList.remove("selected"); i.setAttribute("aria-selected","false"); }); | |
| item.classList.add("selected"); | |
| item.setAttribute("aria-selected","true"); | |
| label.textContent = item.textContent; | |
| if (realSelect.value !== item.dataset.value) { | |
| realSelect.value = item.dataset.value; | |
| realSelect.dispatchEvent(new Event("change", { bubbles: true })); | |
| } | |
| closeMenu(); | |
| trigger.focus(); | |
| } | |
| trigger.setAttribute("tabindex", "0"); | |
| items.forEach(i => i.setAttribute("tabindex", "-1")); | |
| trigger.addEventListener("click", () => { | |
| if (menu.classList.contains("show")) closeMenu(); else openMenu(); | |
| }); | |
| items.forEach(item => { | |
| item.addEventListener("click", () => selectItem(item)); | |
| item.addEventListener("keydown", (e) => { | |
| const idx = items.indexOf(item); | |
| if (e.key === "ArrowDown") { e.preventDefault(); (items[idx+1] || items[0]).focus(); } | |
| else if (e.key === "ArrowUp") { e.preventDefault(); (items[idx-1] || items[items.length-1]).focus(); } | |
| else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); selectItem(item); } | |
| else if (e.key === "Escape") { e.preventDefault(); closeMenu(); trigger.focus(); } | |
| else if (e.key === "Tab") { closeMenu(); } | |
| }); | |
| }); | |
| trigger.addEventListener("keydown", (e) => { | |
| if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") { | |
| e.preventDefault(); openMenu(); | |
| } | |
| }); | |
| document.addEventListener("click", (e) => { | |
| if (!pill.contains(e.target)) closeMenu(); | |
| }); | |
| })(); | |
| </script> | |
| <script> | |
| // Rotating headline – same rolling pattern as Members, but with leaderboard copy | |
| (()=>{ | |
| const el=document.getElementById("rotating-headline"); | |
| if(!el) return; | |
| const phrases=[ | |
| "Every evaluated model, every benchmark, one table.", | |
| "Do you want to compare models?", | |
| "Do you want to beat the best avg?", | |
| "Looking for the smallest mighty model?", | |
| "Dual-mode 7-2026: generative + loglikelihood.", | |
| "Search by org, sort by params.", | |
| "Simple, reliable, open sourced.", | |
| "Got a model to benchmark?" | |
| ]; | |
| const reduce=window.matchMedia("(prefers-reduced-motion: reduce)").matches; | |
| let i=0; | |
| setInterval(()=>{ | |
| i=(i+1)%phrases.length; | |
| if(reduce){ el.textContent=phrases[i]; return; } | |
| el.classList.add("rolling-out"); | |
| el.addEventListener("transitionend", function onOut(){ | |
| el.textContent=phrases[i]; | |
| el.classList.remove("rolling-out"); | |
| el.classList.add("rolling-in"); | |
| requestAnimationFrame(()=>requestAnimationFrame(()=>el.classList.remove("rolling-in"))); | |
| }, {once:true}); | |
| }, 3400); | |
| })(); | |
| </script> | |
| <script src="script.js" defer></script> | |
| </body> | |
| </html> |