Tiny-ML-Leaderboard / index.html
CompactAI's picture
add ivme-conversate-v2-base (#42)
97e6761
Raw
History Blame Contribute Delete
68.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tiny-ML Leaderboard</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3"></script>
<style>
:root {
--bg: #0d1117;
--bg-warm: #161b22;
--card: #161b22;
--card-hover: #1c2129;
--border: #30363d;
--border-light: #21262d;
--text: #c9d1d9;
--text-secondary: #8b949e;
--text-muted: #484f58;
--accent: #58a6ff;
--green: #3fb950;
--orange: #d29922;
--shadow-sm: 0 1px 3px rgba(0,0,0,0.3);
--shadow-md: 0 4px 12px rgba(0,0,0,0.35);
--radius: 12px;
--radius-sm: 8px;
--radius-xs: 6px;
--transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
--glintresearch: #3fb950;
--supralabs: #58a6ff;
--axiomiclabs: #c2b6ff;
--mihaipopa: #93c6aa;
--cromia: #ffffff;
--wop: #ff9b50;
--GODELEV: #1a56db;
--finnianx: #06b6d4;
--ivmelabs: #ff0000;
--rtc: #e8a87c;
--huggingface: #ffcc00;
--facebook: #1877f2;
--openai: #10a37f;
--eleutherai: #ef4444;
--stentor: #ff6bcb;
--eclipsesenpai: #06b6d4;
--minimalabs: #4961e6;
--sandroeth: #84cc16;
--thingai: #b45309;
--veyraai: #d45672;
--fromzero: #d2b48c;
--joelhenwang: #e5e7eb;
--jhuclsp: #2563eb;
--liodonai: #6366f1;
--smalldoge: #ec4899;
--quazim0t0: #0ea5e9;
--small56ai: #22c55e;
--lhtechai: #f97316;
--56m: #a855f7;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
.shell {
max-width: 100%;
margin: 0 auto;
padding: 1.25rem 1.75rem;
}
.welcome { padding: 1rem 0 1.5rem; }
.welcome h1 {
font-size: 1.8rem;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 4px;
}
.welcome p { color: var(--text-secondary); font-size: 0.95rem; }
.stat-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
gap: 12px;
margin-bottom: 1.5rem;
}
.stat-pill {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 1rem 1.15rem;
transition: box-shadow var(--transition), transform var(--transition);
}
.stat-pill:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
.stat-pill .label {
font-size: 0.72rem; font-weight: 600; text-transform: uppercase;
letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 3px;
}
.stat-pill .value { font-size: 1.4rem; font-weight: 700; letter-spacing: -0.02em; }
.stat-pill .sub { font-size: 0.75rem; color: var(--text-secondary); margin-top: 1px; }
.info-banner {
background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-sm);
padding: 1rem 1.15rem; margin-bottom: 1.5rem; font-size: 0.88rem; line-height: 1.6;
display: flex; align-items: flex-start; gap: 10px;
}
.info-banner svg { width: 18px; height: 18px; flex-shrink: 0; margin-top: 2px; color: var(--accent); }
.info-banner a { color: var(--accent); text-decoration: none; }
.info-banner a:hover { text-decoration: underline; }
.info-banner.clickable { cursor: pointer; user-select: none; }
.info-banner.clickable:hover { border-color: var(--accent); }
.banner-expand {
max-height: 0; overflow: hidden;
transition: max-height 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease, margin 0.3s ease;
opacity: 0; margin-top: 0;
}
.banner-expand.open {
max-height: 300px; opacity: 1; margin-top: 10px;
}
.banner-expand-inner {
padding: 0.85rem 1rem; background: var(--bg); border-radius: var(--radius-xs);
border: 1px solid var(--border-light); font-size: 0.84rem; color: var(--text-secondary); line-height: 1.65;
}
.banner-expand-inner code {
background: rgba(88,166,255,0.1); padding: 1px 5px; border-radius: 3px;
font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.82rem; color: var(--accent);
}
.banner-hint {
font-size: 0.75rem; color: var(--text-muted); margin-left: 6px;
transition: transform 0.25s ease; display: inline-block;
}
.banner-hint.rotated { transform: rotate(180deg); }
.section { margin-bottom: 1.1rem; }
.timeline-toolbar {
display: flex; align-items: center; gap: 6px;
margin-bottom: 10px;
overflow-x: auto; -webkit-overflow-scrolling: touch;
scrollbar-width: none;
padding-bottom: 2px;
}
.timeline-toolbar::-webkit-scrollbar { display: none; }
.tl-sep {
width: 1px; height: 18px; background: var(--border);
margin: 0 4px; flex-shrink: 0;
}
.timeline {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
.tl-month {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 16px;
background: var(--bg-warm);
border-bottom: 1px solid var(--border);
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-secondary);
position: sticky;
top: 0;
z-index: 1;
}
.tl-month .tl-month-count {
margin-left: auto;
font-weight: 500;
text-transform: none;
letter-spacing: 0;
color: var(--text-muted);
font-size: 0.74rem;
}
.tl-row {
display: grid;
grid-template-columns: 92px 1fr auto auto;
align-items: center;
gap: 14px;
padding: 11px 16px;
border-bottom: 1px solid var(--border-light);
transition: background var(--transition);
}
.tl-row:last-child { border-bottom: none; }
.tl-row:hover { background: var(--card-hover); }
.tl-date {
font-variant-numeric: tabular-nums;
font-size: 0.8rem;
color: var(--text-muted);
display: flex;
align-items: center;
gap: 8px;
}
.tl-date::before {
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--org-color, var(--text-muted));
flex-shrink: 0;
box-shadow: 0 0 0 3px rgba(255,255,255,0.04);
}
.tl-name {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.tl-name a {
color: var(--text);
text-decoration: none;
font-weight: 600;
font-size: 0.88rem;
letter-spacing: -0.01em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tl-name a:hover { color: var(--accent); }
.tl-params {
font-size: 0.75rem;
color: var(--text-muted);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.tl-org {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 2px 9px;
border-radius: 4px;
font-size: 0.72rem;
font-weight: 600;
white-space: nowrap;
}
@media (max-width: 640px) {
.tl-row {
grid-template-columns: 78px 1fr;
grid-template-areas: "date name" "date extras";
row-gap: 4px;
}
.tl-date { grid-area: date; }
.tl-name { grid-area: name; }
.tl-params { grid-area: extras; justify-self: end; }
.tl-org { grid-area: extras; justify-self: end; }
}
.tl-empty {
padding: 24px 16px;
text-align: center;
color: var(--text-muted);
font-size: 0.84rem;
}
.section-head {
display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem;
}
.section-head h2 { font-size: 1.15rem; font-weight: 700; letter-spacing: -0.02em; }
.section-head .badge {
font-size: 0.72rem; font-weight: 600; padding: 3px 10px; border-radius: 100px;
background: var(--bg-warm); color: var(--text-secondary); border: 1px solid var(--border);
}
.section-head .head-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.sort-control {
display: inline-flex; align-items: center; gap: 6px;
background: var(--bg-warm); border: 1px solid var(--border);
border-radius: 100px; padding: 2px 4px 2px 12px;
font-size: 0.68rem; font-weight: 600; color: var(--text-muted);
text-transform: uppercase; letter-spacing: 0.05em;
}
.sort-control select {
background: transparent; border: none; color: var(--text);
font-size: 0.76rem; font-weight: 600; text-transform: none; letter-spacing: 0;
padding: 4px 26px 4px 8px; border-radius: 100px; cursor: pointer; outline: none;
appearance: none; -webkit-appearance: none; -moz-appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%238b949e' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
background-repeat: no-repeat; background-position: right 8px center;
transition: background-color var(--transition);
}
.sort-control select:hover { background-color: var(--bg); }
.sort-control select:focus { box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.3); }
.sort-control select option { background: var(--bg-warm); color: var(--text); }
.table-wrap {
background: var(--card); border: 1px solid var(--border);
border-radius: var(--radius); overflow: hidden;
}
.table-toolbar {
display: flex; align-items: center; gap: 6px; padding: 8px 12px;
border-bottom: 1px solid var(--border-light); overflow-x: auto; -webkit-overflow-scrolling: touch;
}
.filter-chip {
display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px;
border-radius: 100px; font-size: 0.74rem; font-weight: 500; color: var(--text-secondary);
background: var(--bg); border: 1px solid var(--border); cursor: pointer;
transition: all var(--transition); white-space: nowrap; user-select: none;
}
.filter-chip:hover { border-color: var(--accent); color: var(--text); }
.filter-chip.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.filter-chip .dot { width: 7px; height: 7px; border-radius: 50%; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-height: 78vh; }
table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
thead { position: sticky; top: 0; z-index: 2; }
th {
background: #1c2129; padding: 6px 10px; text-align: left; font-weight: 600;
font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
color: var(--text-muted); border-bottom: 1px solid var(--border); white-space: nowrap;
}
td {
padding: 5px 10px; border-bottom: 1px solid var(--border-light);
transition: background var(--transition);
line-height: 1.3;
}
tr:last-child td { border-bottom: none; }
tbody tr { transition: background var(--transition); }
.lb-row.hover td { background: var(--bg-warm); }
.cell-rank { width: 38px; text-align: center; font-weight: 700; color: var(--text-muted); font-size: 0.78rem; }
.cell-rank .medal { font-size: 1rem; }
.cell-rank.rank-1 { color: #ffd700; }
.cell-rank.rank-2 { color: #c0c0c0; }
.cell-rank.rank-3 { color: #cd7f32; }
.cell-model { min-width: 140px; }
.model-name { font-weight: 600; letter-spacing: -0.01em; font-size: 0.82rem; }
.model-params { font-size: 0.7rem; color: var(--text-muted); margin-top: 1px; }
.org-tag {
display: inline-flex; align-items: center; gap: 4px; padding: 1px 7px;
border-radius: 4px; font-size: 0.7rem; font-weight: 600; white-space: nowrap;
}
.org-tag .org-dot { width: 6px; height: 6px; border-radius: 50%; }
.cell-metric { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; min-width: 68px; font-size: 0.78rem; }
.info-icon { cursor: help; opacity: 0.5; font-size: 0.85em; vertical-align: middle; }
.info-icon:hover { opacity: 1; }
.metric-val { font-weight: 600; font-size: 0.8rem; }
.metric-na { color: var(--text-muted); font-style: italic; font-weight: 400; font-size: 0.72rem; }
.best { color: var(--green); font-weight: 700; }
.cell-links { white-space: nowrap; }
.cell-links a {
display: inline-flex; align-items: center; gap: 3px; padding: 1px 6px;
border-radius: var(--radius-xs); font-size: 0.7rem; font-weight: 500;
color: var(--accent); text-decoration: none; transition: all var(--transition);
}
.cell-links a:hover { background: rgba(88,166,255,0.1); }
.cell-tokens { font-size: 0.76rem; color: var(--text-secondary); white-space: nowrap; }
.cell-date { font-size: 0.74rem; color: var(--text-muted); white-space: nowrap; }
.chart-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 1.25rem;
}
.chart-card {
background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
padding: 1rem; transition: box-shadow var(--transition);
}
.chart-card:hover { box-shadow: var(--shadow-sm); }
.chart-card.full { grid-column: 1 / -1; }
.chart-card h3 { font-size: 0.85rem; font-weight: 600; margin-bottom: 3px; }
.chart-card .chart-sub { font-size: 0.72rem; color: var(--text-muted); margin-bottom: 8px; }
.chart-card canvas { max-height: 420px; }
.legend-bar { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.legend-bar .legend-item { display: flex; align-items: center; gap: 6px; font-size: 0.76rem; color: var(--text-secondary); }
.legend-bar .ldot { width: 8px; height: 8px; border-radius: 50%; }
.eff-note { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 6px; font-size: 0.7rem; color: var(--text-muted); }
.eff-note span { display: flex; align-items: center; gap: 5px; }
.eff-note .line-sample { width: 18px; height: 2px; border-radius: 1px; }
.timeline-bubble-wrap { position: relative; }
.timeline-custom-tooltip {
position: absolute; pointer-events: none; background: #1c2129;
border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px;
font-size: 0.78rem; color: var(--text); box-shadow: var(--shadow-md);
opacity: 0; transition: opacity 0.15s ease; z-index: 10; white-space: nowrap;
}
.timeline-custom-tooltip.visible { opacity: 1; }
.timeline-custom-tooltip .tt-name { font-weight: 600; margin-bottom: 2px; }
.timeline-custom-tooltip .tt-val { color: var(--text-secondary); }
.wiki-bubble-wrap { position: relative; }
.wiki-custom-tooltip {
position: absolute; pointer-events: none; background: #1c2129;
border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px;
font-size: 0.78rem; color: var(--text); box-shadow: var(--shadow-md);
opacity: 0; transition: opacity 0.15s ease; z-index: 10; white-space: nowrap;
}
.wiki-custom-tooltip.visible { opacity: 1; }
.wiki-custom-tooltip .tt-name { font-weight: 600; margin-bottom: 2px; }
.wiki-custom-tooltip .tt-val { color: var(--text-secondary); }
.cta-card {
background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
padding: 1.25rem; display: flex; align-items: center; justify-content: space-between;
gap: 1rem; margin-bottom: 1.5rem; flex-wrap: wrap;
}
.cta-card h3 { font-size: 1rem; font-weight: 700; margin-bottom: 3px; }
.cta-card p { font-size: 0.84rem; color: var(--text-secondary); max-width: 520px; line-height: 1.55; }
.cta-btn {
display: inline-flex; align-items: center; gap: 6px; padding: 9px 18px;
border-radius: var(--radius-sm); background: var(--accent); color: #fff;
font-size: 0.84rem; font-weight: 600; text-decoration: none; border: none;
cursor: pointer; transition: all var(--transition); flex-shrink: 0;
}
.cta-btn:hover { opacity: 0.88; transform: translateY(-1px); box-shadow: var(--shadow-md); }
footer {
margin-top: 1rem; padding: 1.25rem 0; border-top: 1px solid var(--border);
font-size: 0.78rem; color: var(--text-muted); text-align: center; line-height: 1.6;
}
footer a { color: var(--accent); text-decoration: none; }
footer a:hover { text-decoration: underline; }
@keyframes fadeUp {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.anim { animation: fadeUp 0.45s cubic-bezier(0.4,0,0.2,1) both; }
.d1 { animation-delay: .04s; }
.d2 { animation-delay: .08s; }
.d3 { animation-delay: .12s; }
.d4 { animation-delay: .16s; }
.d5 { animation-delay: .20s; }
.d6 { animation-delay: .24s; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 100px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
@media (max-width: 1024px) {
.chart-grid { grid-template-columns: 1fr; }
.chart-card.full { grid-column: 1; }
}
@media (max-width: 768px) {
.shell { padding: 1rem; }
.stat-row { grid-template-columns: repeat(2, 1fr); }
.welcome h1 { font-size: 1.4rem; }
table { font-size: 0.76rem; }
th, td { padding: 7px 8px; }
.cta-card { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 480px) {
.stat-row { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div id="main-content">
<div class="shell">
<div id="submitModal" class="modal-overlay" style="display:none;">
<div class="modal-card">
<span class="close-btn" onclick="closeModal()">&times;</span>
<h3>Agree to Terms</h3>
<p>Before submitting your model, please confirm that you agree to the following terms:</p>
<ul>
<li>Your model uses acc_norm for evaluation.</li>
<li>For WikiText-2 benchmarks, you have used byte perplexity.</li>
</ul>
<button id="modalAgreeBtn" class="cta-btn">I Agree</button>
<button id="modalCancelBtn" class="cta-btn" style="margin-left:10px;background:var(--border);color:var(--text);">Cancel</button>
</div>
</div>
<div class="welcome anim">
<h1>Tiny-ML Leaderboard</h1>
<p>Sub-150M parameter language models, same eval harness, transparent methodology.</p>
</div>
<div class="stat-row anim d1" id="stat-row"></div>
<div class="info-banner anim d2">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
<div>
<strong>Why this exists.</strong> The community deserves a single place to compare tiny LMs fairly.
We include every model with verifiable benchmarks β€” ours, our competitors', yours.
<a href="https://huggingface.co/spaces/Glint-Research/Tiny-ML-Leaderboard/discussions" target="_blank">Submit a model via PR.</a>
</div>
</div>
<div class="info-banner anim d2 clickable" id="unknown-banner" onclick="toggleUnknownBanner()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
<div style="flex:1">
<div style="display:flex;align-items:center;gap:4px;flex-wrap:wrap">
<strong>Unknown org?</strong>
<span>The "Unknown" tag is for model makers submitting their model ahead of official release.</span>
<span>If that's you β€” DM <strong>glintresearch</strong> on Discord.</span>
<span class="banner-hint" id="banner-hint">β–Ό</span>
</div>
<div class="banner-expand" id="banner-expand">
<div class="banner-expand-inner">
Model makers can submit their model's benchmarks before the official release so it appears on the leaderboard immediately when announced. The <strong>Unknown</strong> tag is temporary β€” once you DM <strong>glintresearch</strong> on Discord we can update it to your organization name and color.
</div>
</div>
</div>
</div>
<div class="section anim d3" id="table-section">
<div class="section-head">
<h2>Detailed Results</h2>
<div class="head-right">
<span class="badge" id="model-count-badge"></span>
<div class="sort-control">
<span>Sort</span>
<select id="sort-select" aria-label="Sort leaderboard by">
<option value="efficiency">Efficiency ⚑</option>
<option value="score">Overall Score</option>
<option value="wiki">WikiText-2 byte_ppl</option>
<option value="blimp">BLiMP</option>
<option value="arc">ARC-Easy</option>
<option value="params">Parameters</option>
<option value="date">Release Date</option>
</select>
</div>
</div>
</div>
<div class="table-wrap">
<div class="table-toolbar" id="org-filters"></div>
<div class="table-scroll">
<table>
<thead>
<tr>
<th>#</th>
<th>Model</th>
<th>Org</th>
<th>Params</th>
<th class="cell-metric">Eff. ⚑</th>
<th class="cell-metric">WikiText-2 byte_ppl ↓</th>
<th class="cell-metric">BLiMP ↑</th>
<th class="cell-metric">ARC-Easy ↑</th>
<th>Training Tokens</th>
<th>Released</th>
<th>Links</th>
</tr>
</thead>
<tbody id="leaderboard-body"></tbody>
</table>
</div>
</div>
</div>
<div class="section anim d4" id="timeline-section">
<div class="section-head">
<h2>Model Release Timeline</h2>
<span class="badge">Most recent first</span>
</div>
<div class="timeline" id="timeline-list"></div>
</div>
<div class="section anim d5" id="charts-section">
<div class="section-head"><h2>Benchmark Overview</h2></div>
<div class="legend-bar" id="legend-bar"></div>
<div class="chart-grid">
<div class="chart-card">
<h3>BLiMP ↑</h3>
<p class="chart-sub">Higher is better</p>
<canvas id="blimpChart"></canvas>
</div>
<div class="chart-card">
<h3>ARC-Easy ↑</h3>
<p class="chart-sub">Higher is better</p>
<canvas id="arcChart"></canvas>
</div>
<div class="chart-card full wiki-bubble-wrap">
<h3>WikiText-2 Byte-Level Perplexity ↓</h3>
<p class="chart-sub">Lower is better Β· byte_ppl = exp(βˆ’loglik / total_bytes) Β· bubble size = perplexity (smaller bubble = better)</p>
<canvas id="wikiChart"></canvas>
<div class="wiki-custom-tooltip" id="wikiTooltip">
<div class="tt-name"></div>
<div class="tt-val"></div>
</div>
</div>
</div>
</div>
<div class="section anim d6">
<div class="section-head">
<h2>Model Efficiency</h2>
<span class="badge">Leaderboard Score vs Params</span>
</div>
<div class="chart-grid">
<div class="chart-card full">
<h3>Parameters vs Leaderboard Score</h3>
<p class="chart-sub">Scatter of each model's overall score vs its parameter count. Points above the dashed threshold line are &ge;1&sigma; above the trend. Top 3 marked.</p>
<canvas id="efficiencyChart" style="max-height:400px"></canvas>
<div class="eff-note">
<span><span class="line-sample" style="border-top:2px dashed rgba(255,200,0,0.4)"></span> Avg trend</span>
<span><span class="line-sample" style="border-top:2px dashed rgba(255,200,0,0.8)"></span> High-efficiency threshold</span>
<span><span class="line-sample" style="background:rgba(255,230,0,0.1);height:8px"></span> Outperforming zone</span>
</div>
</div>
<div class="chart-card full">
<h3>Models Released by Org</h3>
<canvas id="orgCountChart" style="max-height:260px"></canvas>
</div>
</div>
</div>
<div class="cta-card anim d5">
<div>
<h3>Add your model</h3>
<p>Open a PR with your model's benchmark results and reproduction steps. We require: params, training data provenance, eval harness used, and scores for all three of the benchmarks using lm-eval harness.</p>
<button id="submitBtn" class="cta-btn" onclick="handleSubmit()">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12h14"/></svg>
Submit Model
</button>
</div>
</div>
<footer>
Tiny-ML Leaderboard by <a href="https://huggingface.co/Glint-Research">Glint Research</a>.
Not affiliated with SupraLabs or LH-Tech-AI.
All benchmark data is self-reported by model authors unless otherwise noted.
</footer>
</div>
</div>
<script>
const models = [
{
name: "MicroSupra-1k",
org: "supralabs",
params: "1K",
blimp: 58.61,
arc: 26.39,
wiki: 11.27,
tokens: "β€”",
releaseDate: "2026-05-13",
links: {
card: "https://huggingface.co/SupraLabs/MicroSupra-1k"
}
},
{
name: "Glint-0.1",
org: "glintresearch",
params: "1M",
blimp: 46.7,
arc: 21,
wiki: 4106963.13,
tokens: "~100M",
releaseDate: "2026-03-09",
links: {
card: "https://huggingface.co/Glint-Research/Glint-0.1"
}
},
{
name: "Supra-Mini-v2",
org: "supralabs",
params: "168K",
blimp: 53.5,
arc: 26.8,
wiki: 7.79,
tokens: "β€”",
releaseDate: "2026-05-12",
links: {
card: "https://huggingface.co/SupraLabs/Supra-Mini-v2-0.1M"
}
},
{
name: "Glint-0.2",
org: "glintresearch",
params: "1M",
blimp: 49.8,
arc: 27,
wiki: 636.4,
tokens: "~100M",
releaseDate: "2026-03-22",
links: {
card: "https://huggingface.co/Glint-Research/Glint-0.2"
}
},
{
name: "Glint-0.3",
org: "glintresearch",
params: "1M",
blimp: 47.3,
arc: 25.5,
wiki: 7.87,
tokens: "~100M",
releaseDate: "2026-04-04",
links: {
card: "https://huggingface.co/Glint-Research/Glint-0.3"
}
},
{
name: "CinnabarLM 1.4M",
org: "mihaipopa",
params: "1.51M",
blimp: 60.7,
arc: 24.58,
wiki: 4.09,
tokens: "~30M",
releaseDate: "2026-05-19",
links: {
card: "https://huggingface.co/MihaiPopa-1/CinnabarLM-1.4M-Base"
}
},
{
name: "Glint-0.4",
org: "glintresearch",
params: "1M",
blimp: 58.5,
arc: 31,
wiki: 5.01,
tokens: "10B",
releaseDate: "2026-04-19",
links: {
card: "https://huggingface.co/Glint-Research/Glint-0.4"
}
},
{
name: "CinnabarLM 1.5M",
org: "mihaipopa",
params: "1.71M",
blimp: 60.51,
arc: 26.68,
wiki: 4.23,
tokens: "~50M",
releaseDate: "2026-05-19",
links: {
card: "https://huggingface.co/MihaiPopa-1/CinnabarLM-1.5M-Base"
}
},
{
name: "PotentSulfurLM 500K",
org: "mihaipopa",
params: "587K",
blimp: 59.01,
arc: 27.06,
wiki: 4.52,
tokens: "~200M",
releaseDate: "2026-05-27",
links: {
card: "https://huggingface.co/MihaiPopa-1/PotentSulfurLM-500K-Base"
}
},
{
name: "MicroLM2-1M",
org: "cromia",
params: "1.71M",
blimp: 54.2,
arc: 27.4,
wiki: 4.82,
tokens: "~4.5B",
releaseDate: "2026-05-22",
links: {
card: "https://huggingface.co/CromIA/MicroLM2-1M"
}
},
{
name: "Glint-1",
org: "glintresearch",
params: "1M",
blimp: 61.2,
arc: 32,
wiki: 4.45,
tokens: "100B",
releaseDate: "2026-05-02",
links: {
card: "https://huggingface.co/Glint-Research/Glint-1"
}
},
{
name: "Supra-Mini-v3",
org: "supralabs",
params: "468K",
blimp: 55.3,
arc: 27.3,
wiki: 4.49,
tokens: "β€”",
releaseDate: "2026-05-14",
links: {
card: "https://huggingface.co/SupraLabs/Supra-Mini-v3-0.5M"
}
},
{
name: "Cosmos-T-80M",
org: "wop",
params: "79.7M",
blimp: 50.47,
arc: 27.82,
wiki: 12.42,
tokens: "~21M",
releaseDate: "2026-05-30",
links: {
card: "https://huggingface.co/wop/Cosmos-T-80M"
}
},
{
name: "Cosmos-T2-80M-Test",
org: "wop",
params: "87.60M",
blimp: 57.61,
arc: 25,
wiki: 11.24,
tokens: "~18M",
releaseDate: "2026-05-31",
links: {
card: "https://huggingface.co/wop/Cosmos-T2-80M-Test"
}
},
{
name: "Supra-Mini-v4",
org: "supralabs",
params: "2.62M",
blimp: 60.7,
arc: 31.5,
wiki: 3.17,
tokens: "β€”",
releaseDate: "2026-05-14",
links: {
card: "https://huggingface.co/SupraLabs/Supra-Mini-v4-2M"
}
},
{
name: "CinnabarLM 4M",
org: "mihaipopa",
params: "4.23M",
blimp: 62.87,
arc: 27.36,
wiki: 3.77,
tokens: "~80M",
releaseDate: "2026-05-05",
links: {
card: "https://huggingface.co/MihaiPopa-1/CinnabarLM-4M-Base"
}
},
{
name: "Cosmos-T2-Accelerate-beta",
org: "wop",
params: "5.03M",
blimp: 54.3,
arc: 26.3,
wiki: 6.26,
tokens: "~22M",
releaseDate: "2026-06-02",
links: {
card: "https://huggingface.co/wop/Cosmos-T2-Accelerate-beta"
}
},
{
name: "Cosmos-T2A-low",
org: "wop",
params: "9.96M",
blimp: 47.8,
arc: 31,
wiki: 5.31,
tokens: "~46.7M",
releaseDate: "2026-06-04",
links: {
card: "https://huggingface.co/wop/Cosmos-T2A-low"
}
},
{
name: "Cosmos-T2-Accelerate-Beta2",
org: "wop",
params: "9.96M",
blimp: 69,
arc: 28,
wiki: 6.72,
tokens: "~10M",
releaseDate: "2026-06-03",
links: {
card: "https://huggingface.co/wop/Cosmos-T2-Accelerate-Beta2"
}
},
{
name: "StorySupra-10M",
org: "supralabs",
params: "12.6M",
blimp: 61.47,
arc: 28.45,
wiki: 8.76,
tokens: "β€”",
releaseDate: "2026-05-15",
links: {
card: "https://huggingface.co/SupraLabs/StorySupra-10M"
}
},
{
name: "Supra-Mini-v5",
org: "supralabs",
params: "7.87M",
blimp: 63.5,
arc: 34.4,
wiki: 2.73,
tokens: "β€”",
releaseDate: "2026-05-16",
links: {
card: "https://huggingface.co/SupraLabs/Supra-Mini-v5-8M"
}
},
{
name: "Cosmos-T2-Accelerate-Preview",
org: "wop",
params: "9.96M",
blimp: 56.95,
arc: 26.8,
wiki: 6.73,
tokens: "462M",
releaseDate: "2026-06-01",
links: {
card: "https://huggingface.co/wop/Cosmos-T2-Accelerate-Preview",
demo: "https://huggingface.co/spaces/wop/Cosmos-T2-Chat"
}
},
{
name: "Glint-1.3 (merged)",
org: "glintresearch",
params: "982K",
blimp: 68.7,
arc: 32.5,
wiki: 3.08,
tokens: "100B",
releaseDate: "2026-05-13",
links: {
card: "https://huggingface.co/Glint-Research/Glint-1.3"
}
},
{
name: "Supra-Mini-v6",
org: "supralabs",
params: "1.41M",
blimp: 61.86,
arc: 30.26,
wiki: 3,
tokens: "β€”",
releaseDate: "2026-05-30",
links: {
card: "https://huggingface.co/SupraLabs/Supra-Mini-v6-1M"
}
},
{
name: "GPT-S-5M",
org: "axiomiclabs",
params: "5.16M",
blimp: 72.27,
arc: 35.69,
wiki: 2.57,
tokens: "25B",
releaseDate: "2026-05-19",
links: {
card: "https://huggingface.co/AxiomicLabs/GPT-S-5M"
}
},
{
name: "Archaea-74M",
org: "GODELEV",
params: "74M",
blimp: 74.91,
arc: 39.06,
wiki: 2.2,
tokens: "~1.2B",
releaseDate: "2026-06-01",
links: {
card: "https://huggingface.co/GODELEV/Archaea-74M"
}
},
{
name: "Supra-50M-Instruct",
org: "supralabs",
params: "51.8M",
blimp: 76.3,
arc: 52.2,
wiki: 2.56,
tokens: "20B",
releaseDate: "2026-05-21",
links: {
card: "https://huggingface.co/SupraLabs/Supra-50M-Instruct",
base: "https://huggingface.co/SupraLabs/Supra-50M-Base"
}
},
{
name: "Michel-Tiny",
org: "finnianx",
params: "55.7M",
blimp: 74.08,
arc: 37.33,
wiki: 2.29,
tokens: "1.3B",
releaseDate: "2026-06-05",
links: {
card: "https://huggingface.co/finnianx/michel-tiny"
}
},
{
name: "Gros-Michel-90m-Base",
org: "finnianx",
params: "91.1M",
blimp: 78.35,
arc: 41.5,
wiki: 2.07,
tokens: "6.5B",
releaseDate: "2026-06-28",
links: {
card: "https://huggingface.co/finnianx/Gros-Michel-90m-Base"
}
},
{
name: "Michel-Nano-v2",
org: "finnianx",
params: "9.94M",
blimp: 72.52,
arc: 35.9,
wiki: 2.46,
tokens: "6.5B",
releaseDate: "2026-06-13",
links: {
card: "https://huggingface.co/finnianx/michel-nano-v2"
}
},
{
name: "Michel-Nano",
org: "finnianx",
params: "5.96M",
blimp: 65.23,
arc: 33.38,
wiki: 3.25,
tokens: "1.1B",
releaseDate: "2026-06-10",
links: {
card: "https://huggingface.co/finnianx/michel-nano"
}
},
{
name: "Gros-Michel-90m-Base-v2",
org: "finnianx",
params: "95M",
blimp: 80.20,
arc: 43.18,
wiki: 2.08,
tokens: "9B",
releaseDate: "2026-07-6",
links: {
card: "https://huggingface.co/finnianx/Gros-Michel-90m-Base-v2"
}
},
{
name: "Michel-Micro",
org: "finnianx",
params: "28.4M",
blimp: 69.75,
arc: 38.59,
wiki: 2.3,
tokens: "2.6B",
releaseDate: "2026-06-09",
links: {
card: "https://huggingface.co/finnianx/michel-micro"
}
},
{
name: "Ivme-Conversate-v1-Base",
org: "ivmelabs",
params: "22.03M",
blimp: 61.4,
arc: 30.85,
wiki: 3.14,
tokens: "~1.57B",
releaseDate: "2026-06-05",
links: {
card: "https://huggingface.co/IvmeLabs/Ivme-Conversate-22M-Base"
}
},
{
name: "kirk-tung",
org: "rtc",
params: "53.1M",
blimp: 72.81,
arc: 30.3,
wiki: 2.38,
tokens: "1.1B",
releaseDate: "2026-06-09",
links: {
card: "https://huggingface.co/rtc2022/kirk-tung"
}
},
{
name: "Supra-Mini-0.1M",
org: "supralabs",
params: "117K",
blimp: 51.77,
arc: 26.39,
wiki: 25.17,
tokens: "500M",
releaseDate: "2026-05-18",
links: {
card: "https://huggingface.co/SupraLabs/Supra-Mini-0.1M"
}
},
{
name: "Supra-50M-Base",
org: "supralabs",
params: "51.8M",
blimp: 76.3,
arc: 46.0,
wiki: 2.04,
tokens: "20B",
releaseDate: "2026-05-27",
links: {
card: "https://huggingface.co/SupraLabs/Supra-50M-Base"
}
},
{
name: "Supra-50M-Reasoning",
org: "supralabs",
params: "51.8M",
blimp: 64.14,
arc: 45.16,
wiki: 2.6,
tokens: "20B",
releaseDate: "2026-06-04",
links: {
card: "https://huggingface.co/SupraLabs/Supra-50M-Reasoning",
demo: "https://huggingface.co/spaces/SupraLabs/Supra-50M-Reasoning-Demo"
}
},
{
name: "Escarda-86M-Base",
org: "quazim0t0",
params: "85.7M",
blimp: 71.44,
arc: 38.01,
wiki: 2.2228,
tokens: "~20B",
releaseDate: "2026-05-22",
links: {
card: "https://huggingface.co/Quazim0t0/Escarda-86M-Base",
discussion: "https://huggingface.co/spaces/Glint-Research/Tiny-ML-Leaderboard/discussions/21"
}
},
{
name: "KeyLM-75M",
org: "minimalabs",
params: "75M",
blimp: 76.10,
arc: 35.65,
wiki: 2.08,
tokens: "~18B",
releaseDate: "2026-05-29",
links: {
card: "https://huggingface.co/MinimaLabs/KeyLM-75M"
}
},
{
name: "KeyLM-75M-Instruct",
org: "minimalabs",
params: "75M",
blimp: 76.02,
arc: 39.10,
wiki: 2.17,
tokens: "~18B",
releaseDate: "2026-05-29",
links: {
card: "https://huggingface.co/MinimaLabs/KeyLM-75M-Instruct",
base: "https://huggingface.co/MinimaLabs/KeyLM-75M"
}
},
{
name: "Glimmer 1",
org: "glintresearch",
params: "11.9K",
blimp: 52.43,
arc: 25.46,
wiki: 14.73,
tokens: "500K",
releaseDate: "2026-06-16",
links: {
card: "https://huggingface.co/Glint-Research/Glimmer-1-Base"
}
},
{
name: "Echo88-150M-Instruct",
org: "exnivo",
params: "150M",
blimp: 72.67,
arc: 31.40,
wiki: 2.45,
tokens: "~1.47B",
releaseDate: "2026-05-05",
links: {
card: "https://huggingface.co/exnivo/Echo88-150M-Instruct"
}
},
{
name: "Byrne-86M-Base",
org: "quazim0t0",
params: "86M",
blimp: 73.56,
arc: 39.31,
wiki: 2.3753,
tokens: "β€”",
releaseDate: "2026-06-18",
links: {
card: "https://huggingface.co/Quazim0t0/Byrne-86M-Base",
base: "https://huggingface.co/Quazim0t0/Byrne-86M"
}
},
{
name: "Byrne-86M",
org: "quazim0t0",
params: "86M",
blimp: 70.33,
arc: 34.68,
wiki: 2.6839,
tokens: "β€”",
releaseDate: "2026-06-18",
links: {
card: "https://huggingface.co/Quazim0t0/Byrne-86M",
base: "https://huggingface.co/Quazim0t0/Byrne-86M-Base"
}
},
{
name: "Blink-1-Base",
org: "glintresearch",
params: "1.09K",
blimp: 52.84,
arc: 26.60,
wiki: 71.35,
tokens: "100B",
releaseDate: "2026-06-21",
links: {
card: "https://huggingface.co/Glint-Research/Blink-1-Base"
}
},
{
name: "Blink-1-Instruct",
org: "glintresearch",
params: "1.09K",
blimp: 52.46,
arc: 26.80,
wiki: 70.44,
tokens: "100B",
releaseDate: "2026-06-21",
links: {
card: "https://huggingface.co/Glint-Research/Blink-1-Base",
base: "https://huggingface.co/Glint-Research/Blink-1-Base"
}
},
{
name: "Dumb-1.2-Preview-0625",
org: "56m",
params: "34.6M",
blimp: 64.05,
arc: 32.79,
wiki: 2.875,
tokens: "~115~165M",
releaseDate: "2026-06-25",
links: {
card: "https://huggingface.co/56m/Dumb-1.2-Preview-0625"
}
},
{
name: "Dumb-1.2-RC1",
org: "56m",
params: "34.6M",
blimp: 64.87,
arc: 34.13,
wiki: 2.838,
tokens: "210M",
releaseDate: "2026-06-28",
links: {
card: "https://huggingface.co/56m/Dumb-1.2-RC1"
}
},
{
name: "GPT-X2-125M",
org: "axiomiclabs",
params: "125M",
blimp: 81.28,
arc: 57.07,
wiki: 1.86,
tokens: "75B",
releaseDate: "2026-04-22",
links: {
card: "https://huggingface.co/AxiomicLabs/GPT-X2-125M"
}
},
{
name: "Unknown-2026-0628",
org: "unknown",
params: "34.6M",
blimp: 64.28,
arc: 32.09,
wiki: 2.872,
tokens: "β€”",
links: {}
},
{
name: "TinyMoE-100m-2x8",
org: "flamef0x",
params: "99.8M",
blimp: 61.13,
arc: 25.88,
wiki: 3.878,
tokens: "~625M",
releaseDate: "2026-06-15",
links: {
card: "https://huggingface.co/FlameF0X/TinyMoE-100m-2x8"
}
},
{
name: "TinyMoE-100m-2x8-retrained",
org: "flamef0x",
params: "99.8M",
blimp: 66.01,
arc: 33.88,
wiki: 2.879,
tokens: "β€”",
releaseDate: "2026-07-05",
links: {
card: "https://huggingface.co/FlameF0X/TinyMoE-100m-2x8-retrained"
}
},
{
name: "SRLM-1M",
org: "martico2432",
params: "904k",
blimp: 53.1,
arc: 28.66,
wiki: 4.455,
tokens: "~16M",
releaseDate: "2026-07-04",
links: {
card: "https://huggingface.co/Martico2432/srlm-1m"
}
},
{
name: "Ivme-Conversate-v2-Base",
org: "ivmelabs",
params: "23.85M",
blimp: 75.09,
arc: 39.98,
wiki: 2.2250,
tokens: "~12.85B",
releaseDate: "2026-07-07",
links: {
card: "https://huggingface.co/IvmeLabs/Ivme-Conversate-v2-Base",
demo: "https://huggingface.co/spaces/IvmeLabs/Ivme-Conversate-Demo"
}
},
];
const orgNameMap = {
glintresearch: 'Glint Research',
supralabs: 'SupraLabs',
axiomiclabs: 'Axiomic Labs',
mihaipopa: 'Mihai Popa',
cromia: 'CromIA',
wop: 'wop',
GODELEV: 'GODELEV',
finnianx: 'finnianx',
ivmelabs: 'IvmeLabs',
rtc: 'RTC',
huggingface: 'HuggingFace',
facebook: 'Meta',
openai: 'OpenAI',
eleutherai: 'EleutherAI',
stentor: 'StentorLabs',
eclipsesenpai: 'Eclipse-Senpai',
minimalabs: 'Minima Labs',
sandroeth: 'Sandroeth',
thingai: 'ThingAI',
veyraai: 'veyra-ai',
fromzero: 'FromZero',
joelhenwang: 'joelhenwang',
jhuclsp: 'JHU CLSP',
liodonai: 'Liodon AI',
smalldoge: 'SmallDoge',
quazim0t0: 'Quazim0t0',
small56ai: 'Small56.AI',
lhtechai: 'LH-Tech-AI',
harleyml: 'Harley ML',
exnivo: 'Exnivo',
'56m': '56m',
unknown: 'Unknown',
flamef0x: 'FlameF0X',
martico2432: 'Martico2432'
};
const colorMap = {
glintresearch: '#3fb950',
supralabs: '#58a6ff',
axiomiclabs: '#c2b6ff',
mihaipopa: '#93c6aa',
cromia: '#d0d7de',
wop: '#ff9b50',
GODELEV: '#1a56db',
finnianx: '#06b6d4',
ivmelabs: '#ff0000',
rtc: '#e8a87c',
huggingface: '#ffcc00',
facebook: '#1877f2',
openai: '#10a37f',
eleutherai: '#ef4444',
stentor: '#ff6bcb',
eclipsesenpai: '#06b6d4',
minimalabs: '#4961e6',
sandroeth: '#84cc16',
thingai: '#b45309',
veyraai: '#d45672',
fromzero: '#d2b48c',
joelhenwang: '#9ca3af',
jhuclsp: '#2563eb',
liodonai: '#6366f1',
smalldoge: '#ec4899',
quazim0t0: '#0ea5e9',
small56ai: '#22c55e',
lhtechai: '#f97316',
exnivo: '#8B4513',
unknown: '#fbbf24',
'56m': '#a855f7',
flamef0x: '#cc5218',
martico2432: '#6cf01a'
};
const bgMap = {};
Object.keys(colorMap).forEach(k => {
const c = colorMap[k];
const r = parseInt(c.slice(1, 3), 16);
const g = parseInt(c.slice(3, 5), 16);
const b = parseInt(c.slice(5, 7), 16);
bgMap[k] = `rgba(${r},${g},${b},0.7)`;
});
function parseParams(s) {
if (!s || typeof s !== 'string') return NaN;
const u = s.toUpperCase().replace(/,/g, '');
if (u.endsWith('B')) return parseFloat(u) * 1e9;
if (u.endsWith('M')) return parseFloat(u) * 1e6;
if (u.endsWith('K')) return parseFloat(u) * 1e3;
return parseFloat(u) || NaN;
}
const WIKI_PPL_CAP = 500;
const wikiScoreLogs = models
.filter(m => m.wiki !== null && typeof m.wiki === 'number' && m.wiki > 0)
.map(m => Math.log(Math.min(m.wiki, WIKI_PPL_CAP)));
const wikiMinLog = Math.min(...wikiScoreLogs);
const wikiMaxLog = Math.max(...wikiScoreLogs);
function getWikiScore(m) {
if (m.wiki === null || typeof m.wiki !== 'number' || m.wiki <= 0 || wikiMinLog === wikiMaxLog) return null;
const cappedLog = Math.log(Math.min(m.wiki, WIKI_PPL_CAP));
const normalized = 1 - ((cappedLog - wikiMinLog) / (wikiMaxLog - wikiMinLog));
return Math.max(0, Math.min(1, normalized)) * 100;
}
function getScore(m) {
const wikiScore = getWikiScore(m);
const hasBlimp = typeof m.blimp === 'number';
const hasArc = typeof m.arc === 'number';
const hasWiki = wikiScore !== null;
if (!hasBlimp && !hasArc && !hasWiki) return -1;
const blimpScore = hasBlimp ? m.blimp : 0;
const arcScore = hasArc ? m.arc : 0;
const wikiVal = hasWiki ? wikiScore : 0;
return (blimpScore + arcScore + wikiVal) / 3;
}
function getEfficiencyScore(m) {
const score = getScore(m);
if (score <= 0) return -1;
return score;
}
function orgTint(orgKey, alpha) {
const c = colorMap[orgKey];
const r = parseInt(c.slice(1, 3), 16);
const g = parseInt(c.slice(3, 5), 16);
const b = parseInt(c.slice(5, 7), 16);
return `rgba(${r},${g},${b},${alpha})`;
}
const worstGreen = [255, 255, 255];
const bestGreen = [63, 185, 80];
function getColor(value, min, max, lowerIsBetter, useLog = false) {
if (value === null || isNaN(value) || min === max) return '';
let v = value, mn = min, mx = max;
if (useLog) { v = Math.log(v); mn = Math.log(mn); mx = Math.log(mx); }
let p = (v - mn) / (mx - mn);
if (lowerIsBetter) p = 1 - p;
const a = Math.pow(Math.max(0, Math.min(1, p)), 2.5);
const r = Math.round(worstGreen[0] + (bestGreen[0] - worstGreen[0]) * a);
const g = Math.round(worstGreen[1] + (bestGreen[1] - worstGreen[1]) * a);
const b = Math.round(worstGreen[2] + (bestGreen[2] - worstGreen[2]) * a);
return `color:rgb(${r},${g},${b})`;
}
/* ─── Stats ─── */
function renderStats() {
const orgs = new Set(models.map(m => m.org));
const blimps = models.filter(m => m.blimp).map(m => m.blimp);
const arcs = models.filter(m => m.arc).map(m => m.arc);
const bestB = Math.max(...blimps);
const bestA = Math.max(...arcs);
document.getElementById('stat-row').innerHTML = `
<div class="stat-pill"><div class="label">Models</div><div class="value">${models.length}</div><div class="sub">On leaderboard</div></div>
<div class="stat-pill"><div class="label">Organizations</div><div class="value">${orgs.size}</div><div class="sub">Contributing</div></div>
<div class="stat-pill"><div class="label">Best BLiMP</div><div class="value" style="color:var(--green)">${bestB}%</div><div class="sub">${models.find(m => m.blimp === bestB).name}</div></div>
<div class="stat-pill"><div class="label">Best ARC-E</div><div class="value" style="color:var(--green)">${bestA}%</div><div class="sub">${models.find(m => m.arc === bestA).name}</div></div>
`;
document.getElementById('model-count-badge').textContent = `${models.length} models`;
}
/* ─── Filters ─── */
let activeFilter = 'all';
let activeSort = 'efficiency';
const sortComparators = {
score: (a, b) => getScore(b) - getScore(a),
wiki: (a, b) => {
if (a.wiki == null) return 1;
if (b.wiki == null) return -1;
return a.wiki - b.wiki;
},
blimp: (a, b) => {
if (a.blimp == null) return 1;
if (b.blimp == null) return -1;
return b.blimp - a.blimp;
},
arc: (a, b) => {
if (a.arc == null) return 1;
if (b.arc == null) return -1;
return b.arc - a.arc;
},
efficiency: (a, b) => getEfficiencyScore(b) - getEfficiencyScore(a),
params: (a, b) => parseParams(a.params) - parseParams(b.params),
date: (a, b) => {
if (!a.releaseDate) return 1;
if (!b.releaseDate) return -1;
return new Date(b.releaseDate) - new Date(a.releaseDate);
}
};
function sizeBucket(params) {
const n = parseParams(params);
if (isNaN(n) || n < 1e6) return 'small';
if (n < 1e7) return 'medium';
return 'large';
}
function matchesFilter(m) {
if (activeFilter === 'all') return true;
if (activeFilter === 'small' || activeFilter === 'medium' || activeFilter === 'large') {
return sizeBucket(m.params) === activeFilter;
}
return m.org === activeFilter;
}
function getFilteredModels() {
return models.filter(matchesFilter);
}
function setupSortControl() {
const sel = document.getElementById('sort-select');
if (!sel) return;
sel.value = activeSort;
sel.addEventListener('change', e => {
activeSort = e.target.value;
renderTable();
});
}
function renderFilteredViews() {
renderTable();
buildLegend();
renderTimeline();
buildBarChart('blimpChart', 'blimp', false);
buildBarChart('arcChart', 'arc', false);
buildWikiChart();
buildEfficiencyChart();
buildOrgCountChart();
}
function buildFilters() {
const tb = document.getElementById('org-filters');
if (!tb) return;
const sizeChips = [
{ key: 'all', label: 'All' },
{ key: 'small', label: '< 1M' },
{ key: 'medium', label: '1–10M' },
{ key: 'large', label: '10M+' }
];
sizeChips.forEach(({ key, label }) => {
const c = document.createElement('div');
c.className = 'filter-chip' + (key === 'all' ? ' active' : '');
c.dataset.filter = key;
c.textContent = label;
tb.appendChild(c);
});
const sep = document.createElement('div');
sep.className = 'tl-sep';
tb.appendChild(sep);
const orgs = [...new Set(models.map(m => m.org))];
orgs.forEach(org => {
const c = document.createElement('div');
c.className = 'filter-chip';
c.dataset.filter = org;
c.innerHTML = `<span class="dot" style="background:${colorMap[org]}"></span>${orgNameMap[org]}`;
tb.appendChild(c);
});
tb.addEventListener('click', e => {
const chip = e.target.closest('.filter-chip');
if (!chip) return;
tb.querySelectorAll('.filter-chip').forEach(c => c.classList.remove('active'));
chip.classList.add('active');
activeFilter = chip.dataset.filter;
renderFilteredViews();
});
}
/* ─── Table ─── */
function formatDate(dateStr) {
if (!dateStr) return 'β€”';
const date = new Date(dateStr);
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
}
function renderTable() {
const tbody = document.getElementById('leaderboard-body');
const cmp = sortComparators[activeSort] || sortComparators.score;
const filtered = getFilteredModels().sort(cmp);
document.getElementById('model-count-badge').textContent = activeFilter === 'all'
? `${models.length} models`
: `${filtered.length} of ${models.length} models`;
const blimps = models.filter(m => m.blimp).map(m => m.blimp);
const arcs = models.filter(m => m.arc).map(m => m.arc);
const wikis = models.filter(m => m.wiki).map(m => m.wiki);
const effs = models.filter(m => getEfficiencyScore(m) >= 0).map(m => getEfficiencyScore(m));
const bMin = Math.min(...blimps), bMax = Math.max(...blimps);
const aMin = Math.min(...arcs), aMax = Math.max(...arcs);
const wMin = Math.min(...wikis), wMax = Math.max(...wikis);
const eMin = Math.min(...effs), eMax = Math.max(...effs);
tbody.innerHTML = filtered.map((m, idx) => {
const oc = colorMap[m.org];
const orgBg = orgTint(m.org, 0.15);
const isBestBlimp = m.blimp && m.blimp === bMax;
const isBestArc = m.arc && m.arc === aMax;
const isBestWiki = m.wiki && m.wiki === wMin;
const rank = idx + 1;
const rankClass = rank <= 3 ? ` rank-${rank}` : '';
return `<tr class="lb-row" onmouseenter="this.classList.add('hover')" onmouseleave="this.classList.remove('hover')">
<td class="cell-rank${rankClass}">#${rank}</td>
<td class="cell-model">
<div class="model-name">${m.name}</div>
</td>
<td><span class="org-tag" style="background:${orgBg};color:${oc}"><span class="org-dot" style="background:${oc}"></span>${orgNameMap[m.org]}</span></td>
<td>${m.params}</td>
<td class="cell-metric" style="${getColor(getEfficiencyScore(m), eMin, eMax, false)}">
${getEfficiencyScore(m) >= 0
? `<span class="metric-val${getEfficiencyScore(m) >= eMax ? ' best' : ''}">${getEfficiencyScore(m).toFixed(2)}</span>`
: '<span class="metric-na">TBD</span>'}
</td>
<td class="cell-metric ${m.wiki === null ? '' : ''}" style="${getColor(m.wiki, wMin, wMax, true, true)}">
${m.wiki !== null
? `<span class="metric-val${isBestWiki ? ' best' : ''}">${m.wiki}</span>`
: '<span class="metric-na">TBD</span>'}
</td>
<td class="cell-metric" style="${getColor(m.blimp, bMin, bMax, false)}">
${m.blimp !== null
? `<span class="metric-val${isBestBlimp ? ' best' : ''}">${m.blimp}%</span>`
: '<span class="metric-na">TBD</span>'}
</td>
<td class="cell-metric" style="${getColor(m.arc, aMin, aMax, false)}">
${m.arc !== null
? `<span class="metric-val${isBestArc ? ' best' : ''}">${m.arc}%</span>`
: '<span class="metric-na">TBD</span>'}
</td>
<td class="cell-tokens">${m.tokens}</td>
<td class="cell-date">${formatDate(m.releaseDate)}</td>
<td class="cell-links">
${m.links.card ? `<a href="${m.links.card}" target="_blank">card</a>` : '<span class="metric-na">β€”</span>'}
${m.links.base ? `<a href="${m.links.base}" target="_blank">base</a>` : ''}
${m.links.demo ? `<a href="${m.links.demo}" target="_blank">demo</a>` : ''}
</td>
</tr>`;
}).join('');
}
/* ─── Legend ─── */
function buildLegend() {
const bar = document.getElementById('legend-bar');
const orgs = [...new Set(getFilteredModels().map(m => m.org))];
bar.innerHTML = orgs.map(org =>
`<span class="legend-item"><span class="ldot" style="background:${colorMap[org]}"></span>${orgNameMap[org]}</span>`
).join('');
}
/* ─── Chart defaults ─── */
Chart.defaults.color = '#8b949e';
Chart.defaults.borderColor = 'rgba(255,255,255,0.06)';
Chart.defaults.font.family = "-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif";
Chart.defaults.font.size = 11;
Chart.defaults.plugins.legend.display = false;
const tooltipStyle = {
backgroundColor: '#1c2129',
titleColor: '#c9d1d9',
bodyColor: '#8b949e',
borderColor: '#30363d',
borderWidth: 1,
cornerRadius: 8,
padding: 10,
displayColors: false
};
/* ─── Timeline ─── */
function renderTimeline() {
const container = document.getElementById('timeline-list');
if (!container) return;
const sorted = getFilteredModels()
.filter(m => m.releaseDate)
.sort((a, b) => new Date(b.releaseDate) - new Date(a.releaseDate));
const monthKey = d => {
const [y, m] = d.split('-');
return `${y}-${m}`;
};
const monthLabel = key => {
const [y, m] = key.split('-');
const dt = new Date(parseInt(y), parseInt(m) - 1, 1);
return dt.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
};
const dayLabel = d => {
const [y, m, day] = d.split('-').map(Number);
const dt = new Date(y, m - 1, day);
return dt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
};
if (sorted.length === 0) {
container.innerHTML = '<div class="tl-empty">No models match this filter.</div>';
return;
}
const groups = {};
sorted.forEach(m => {
const k = monthKey(m.releaseDate);
(groups[k] = groups[k] || []).push(m);
});
container.innerHTML = Object.keys(groups).map(key => {
const items = groups[key];
const rows = items.map(m => {
const oc = colorMap[m.org];
const orgBg = orgTint(m.org, 0.15);
return `<div class="tl-row" style="--org-color:${oc}">
<div class="tl-date">${dayLabel(m.releaseDate)}</div>
<div class="tl-name">
<a href="${m.links.card}" target="_blank" rel="noopener">${m.name}</a>
</div>
<div class="tl-params">${m.params} params</div>
<div class="tl-org" style="background:${orgBg};color:${oc}">${orgNameMap[m.org]}</div>
</div>`;
}).join('');
return `<div class="tl-month">
<span>${monthLabel(key)}</span>
<span class="tl-month-count">${items.length} model${items.length === 1 ? '' : 's'}</span>
</div>${rows}`;
}).join('');
}
/* ─── Bar charts ─── */
function buildBarChart(canvasId, metric, reverse) {
const canvas = document.getElementById(canvasId);
const existing = Chart.getChart(canvas);
if (existing) existing.destroy();
const fmt = v => v.toFixed(1) + '%';
const sorted = getFilteredModels()
.filter(d => d[metric] !== null && typeof d[metric] === 'number')
.sort((a, b) => reverse ? a[metric] - b[metric] : b[metric] - a[metric]);
new Chart(canvas, {
type: 'bar',
data: {
labels: sorted.map(d => d.name),
datasets: [{
data: sorted.map(d => d[metric]),
backgroundColor: sorted.map(d => bgMap[d.org]),
borderColor: sorted.map(d => colorMap[d.org]),
borderWidth: 1,
borderRadius: 3,
borderSkipped: false
}]
},
options: {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
animation: { duration: 600, easing: 'easeOutQuart' },
plugins: {
tooltip: {
callbacks: { label: ctx => fmt(ctx.parsed.x) },
...tooltipStyle
}
},
scales: {
x: {
beginAtZero: true,
grid: { drawBorder: false },
ticks: { callback: v => v + '%' }
},
y: {
grid: { display: false },
ticks: {
font: { size: 9 },
autoSkip: false,
callback: function(v) {
const l = this.getLabelForValue(v);
return l.length > 18 ? l.slice(0, 17) + '…' : l;
}
}
}
}
}
});
}
/* ─── WikiText-2 Bubble ─── */
function buildWikiChart() {
const canvas = document.getElementById('wikiChart');
const existing = Chart.getChart(canvas);
if (existing) existing.destroy();
const data = getFilteredModels()
.filter(d => d.wiki !== null && typeof d.wiki === 'number')
.filter(d => d.name !== 'Glint-0.1' && d.name !== 'Glint-0.2')
.map(d => ({
name: d.name,
org: d.org,
wiki: d.wiki,
logWiki: Math.log10(Math.max(d.wiki, 0.1)),
params: d.params
}))
.sort((a, b) => a.wiki - b.wiki);
const ySpread = [];
const used = [];
data.forEach(d => {
let y = 0.5;
const logX = d.logWiki;
for (let attempt = 0; attempt < 40; attempt++) {
const candidateY = 0.15 + (attempt % 8) * 0.1 + Math.floor(attempt / 8) * 0.02;
let overlap = false;
for (const u of used) {
const dx = Math.abs(logX - u.logX);
const dy = Math.abs(candidateY - u.y);
if (dx < 0.15 && dy < 0.08) { overlap = true; break; }
}
if (!overlap) { y = candidateY; break; }
}
used.push({ logX, y });
ySpread.push(y);
});
const logVals = data.map(d => d.logWiki);
const logMin = Math.min(...logVals);
const logMax = Math.max(...logVals);
function getRadius(logW) {
if (logMax === logMin) return 12;
const t = (logW - logMin) / (logMax - logMin);
return 6 + t * 26;
}
const tooltip = document.getElementById('wikiTooltip');
tooltip.classList.remove('visible');
new Chart(canvas, {
type: 'bubble',
data: {
datasets: [{
data: data.map((d, i) => ({
x: d.wiki,
y: ySpread[i],
r: getRadius(d.logWiki),
_name: d.name,
_org: d.org,
_wiki: d.wiki,
_params: d.params
})),
backgroundColor: data.map(d => orgTint(d.org, 0.5)),
borderColor: data.map(d => colorMap[d.org]),
borderWidth: 1.5,
hoverBorderWidth: 2.5,
hoverBackgroundColor: data.map(d => orgTint(d.org, 0.75))
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
animation: { duration: 700, easing: 'easeOutQuart' },
layout: { padding: { top: 10, bottom: 10, left: 10, right: 10 } },
scales: {
x: {
type: 'logarithmic',
title: { display: true, text: 'byte_ppl (log scale)', color: '#8b949e', font: { size: 11 } },
grid: { drawBorder: false, color: 'rgba(255,255,255,0.04)' },
ticks: {
color: '#8b949e',
callback: function(v) {
if (v >= 1000) return (v / 1000).toFixed(v >= 10000 ? 0 : 1) + 'K';
if (v >= 1) return v.toFixed(v >= 100 ? 0 : v >= 10 ? 1 : 2);
return v.toString();
}
}
},
y: { display: false, min: 0, max: 1 }
},
plugins: {
legend: { display: false },
tooltip: { enabled: false }
}
},
plugins: [
{
id: 'customLabels',
afterDraw(chart) {
const ctx = chart.ctx;
const meta = chart.getDatasetMeta(0);
meta.data.forEach((point, i) => {
const d = chart.data.datasets[0].data[i];
if (d.r >= 12) {
ctx.save();
ctx.font = `500 ${Math.min(d.r * 0.55, 11)}px -apple-system,BlinkMacSystemFont,sans-serif`;
ctx.fillStyle = 'rgba(255,255,255,0.85)';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
let label = d._name;
const maxW = d.r * 1.6;
if (ctx.measureText(label).width > maxW) {
label = label.slice(0, Math.floor(maxW / ctx.measureText('A').width)) + '…';
}
ctx.fillText(label, point.x, point.y);
ctx.restore();
}
});
}
},
{
id: 'customTooltip',
afterEvent(chart, args) {
const evt = args.event;
if (evt.type === 'mouseout') {
tooltip.classList.remove('visible');
return;
}
const elements = chart.getElementsAtEventForMode(evt, 'nearest', { intersect: true }, false);
if (elements.length > 0) {
const el = elements[0];
const d = chart.data.datasets[0].data[el.index];
const point = chart.getDatasetMeta(0).data[el.index];
tooltip.querySelector('.tt-name').textContent = d._name;
tooltip.querySelector('.tt-val').innerHTML =
`byte_ppl: <strong>${d._wiki.toLocaleString()}</strong> Β· ${d._params} params`;
let left = point.x + 14;
let top = point.y - 20;
const ttW = 250;
if (left + ttW > canvas.width) left = point.x - ttW - 10;
if (top < 0) top = 10;
tooltip.style.left = left + 'px';
tooltip.style.top = top + 'px';
tooltip.classList.add('visible');
} else {
tooltip.classList.remove('visible');
}
}
}
]
});
}
/* ─── Efficiency ─── */
function buildEfficiencyChart() {
const canvas = document.getElementById('efficiencyChart');
const existing = Chart.getChart(canvas);
if (existing) existing.destroy();
const valid = getFilteredModels()
.filter(d => getScore(d) >= 0)
.filter(d => d.name !== 'MicroSupra-1k')
.map(d => ({ ...d, paramsNum: parseParams(d.params), avgScore: getScore(d) }))
.filter(d => !isNaN(d.paramsNum) && d.paramsNum > 0);
if (valid.length < 2) return;
const ranked = [...valid].sort((a, b) => b.avgScore - a.avgScore);
const rankMap = new Map();
ranked.forEach((m, i) => rankMap.set(m.name, i + 1));
valid.forEach(m => m.rank = rankMap.get(m.name));
const logP = valid.map(d => Math.log10(d.paramsNum));
const scores = valid.map(d => d.avgScore);
const n = valid.length;
const sx = logP.reduce((a, v) => a + v, 0);
const sy = scores.reduce((a, v) => a + v, 0);
const sxy = logP.reduce((a, v, i) => a + v * scores[i], 0);
const sx2 = logP.reduce((a, v) => a + v * v, 0);
const slope = (n * sxy - sx * sy) / (n * sx2 - sx * sx);
const intercept = (sy - slope * sx) / n;
const res = valid.map(d => d.avgScore - (intercept + slope * Math.log10(d.paramsNum)));
const resStd = Math.sqrt(res.reduce((a, v) => a + v * v, 0) / n);
const shift = Math.max(resStd, 3);
const sorted = [...valid].sort((a, b) => a.paramsNum - b.paramsNum);
const axMin = 500, axMax = 1.5e8;
const regData = [], threshData = [];
for (let i = 0; i <= 80; i++) {
const lx = Math.log10(axMin) + (Math.log10(axMax) - Math.log10(axMin)) * (i / 80);
const x = Math.pow(10, lx);
regData.push({ x, y: intercept + slope * lx });
threshData.push({ x, y: intercept + slope * lx + shift });
}
new Chart(canvas, {
type: 'line',
data: {
datasets: [
{
label: 'Models',
data: sorted.map(d => ({ x: d.paramsNum, y: d.avgScore })),
showLine: false,
backgroundColor: sorted.map(d => colorMap[d.org]),
borderColor: sorted.map(d => colorMap[d.org]),
pointRadius: 6,
pointHoverRadius: 9
},
{
label: 'Trend',
data: regData,
showLine: true,
borderColor: 'rgba(255,200,0,0.5)',
borderWidth: 1.5,
borderDash: [4, 4],
pointRadius: 0,
fill: false
},
{
label: 'Threshold',
data: threshData,
showLine: true,
borderColor: 'rgba(255,200,0,0.8)',
borderWidth: 2,
borderDash: [6, 4],
pointRadius: 0,
fill: false
}
]
},
options: {
parsing: false,
responsive: true,
maintainAspectRatio: true,
animation: { duration: 700, easing: 'easeOutQuart' },
scales: {
x: {
type: 'logarithmic',
min: axMin,
max: axMax,
title: { display: true, text: 'Parameters', color: '#8b949e' },
grid: { drawBorder: false },
ticks: {
color: '#8b949e',
callback: v => v >= 1e6
? (v / 1e6).toFixed(v >= 1e7 ? 0 : 1) + 'M'
: v >= 1e3
? (v / 1e3).toFixed(v >= 1e4 ? 0 : 1) + 'K'
: v.toString()
}
},
y: {
title: { display: true, text: 'Leaderboard Score (avg of available benchmarks)', color: '#8b949e' },
min: 20,
max: 80,
grid: { drawBorder: false },
ticks: { color: '#8b949e', callback: v => v + '%' }
}
},
plugins: {
legend: { display: false },
tooltip: {
callbacks: {
label: ctx => {
if (ctx.dataset.label !== 'Models') return '';
const d = sorted[ctx.dataIndex];
return `#${d.rank} ${d.name}: ${d.params}, ${d.avgScore.toFixed(1)}%`;
}
},
...tooltipStyle
}
}
},
plugins: [
{
id: 'zone',
beforeDraw(chart) {
const ctx = chart.ctx, xs = chart.scales.x, ys = chart.scales.y;
const { left, right, top, bottom } = chart.chartArea;
const lY = intercept + slope * Math.log10(Math.max(xs.min, 1)) + shift;
const rY = intercept + slope * Math.log10(Math.max(xs.max, 1)) + shift;
ctx.save();
ctx.beginPath();
ctx.rect(left, top, right - left, bottom - top);
ctx.clip();
ctx.beginPath();
ctx.moveTo(left, ys.getPixelForValue(lY));
ctx.lineTo(left, top);
ctx.lineTo(right, top);
ctx.lineTo(right, ys.getPixelForValue(rY));
ctx.closePath();
ctx.fillStyle = 'rgba(255,230,0,0.06)';
ctx.fill();
ctx.restore();
}
},
{
id: 'rankLabels',
afterDatasetsDraw(chart) {
const ctx = chart.ctx;
const meta = chart.getDatasetMeta(0);
const medalColors = { 1: '#ffd700', 2: '#c0c0c0', 3: '#cd7f32' };
meta.data.forEach((point, i) => {
const d = sorted[i];
if (d.rank <= 3) {
ctx.save();
ctx.font = '700 10px -apple-system,BlinkMacSystemFont,sans-serif';
ctx.fillStyle = medalColors[d.rank];
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText(`#${d.rank}`, point.x + 11, point.y - 1);
ctx.restore();
}
});
}
}
]
});
}
/* ─── Org Count ─── */
function buildOrgCountChart() {
const canvas = document.getElementById('orgCountChart');
const existing = Chart.getChart(canvas);
if (existing) existing.destroy();
const counts = {};
getFilteredModels().forEach(m => counts[m.org] = (counts[m.org] || 0) + 1);
const orgs = Object.keys(counts).sort((a, b) => counts[b] - counts[a]);
new Chart(canvas, {
type: 'doughnut',
data: {
labels: orgs.map(o => orgNameMap[o]),
datasets: [{
data: orgs.map(o => counts[o]),
backgroundColor: orgs.map(o => colorMap[o]),
borderColor: '#161b22',
borderWidth: 2,
hoverOffset: 6
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
cutout: '58%',
animation: { duration: 700, easing: 'easeOutQuart' },
plugins: {
legend: {
display: true,
position: 'bottom',
labels: {
color: '#c9d1d9',
padding: 14,
usePointStyle: true,
pointStyle: 'circle',
font: { size: 11 }
}
}
}
}
});
}
/* ─── Toggle Banner ─── */
function toggleUnknownBanner() {
const expand = document.getElementById('banner-expand');
const hint = document.getElementById('banner-hint');
if (!expand) return;
const isOpen = expand.classList.contains('open');
expand.classList.toggle('open');
if (hint) hint.classList.toggle('rotated');
}
/* Modal functions */
function closeModal() {
document.getElementById('submitModal').style.display = 'none';
}
function handleSubmit() {
document.getElementById('submitModal').style.display = 'flex';
}
document.getElementById('modalAgreeBtn').addEventListener('click', function() {
document.getElementById('submitModal').style.display = 'none';
const randomNum = Math.floor(Math.random() * 100000);
const agreementText = 'I agreed to terms. Please include this number in your submission: ' + randomNum;
document.getElementById('submitBtn').innerHTML = agreementText;
document.getElementById('submitBtn').onclick = null;
setTimeout(function() {
window.open('https://huggingface.co/spaces/Glint-Research/Tiny-ML-Leaderboard/discussions', '_blank');
}, 1500);
});
document.getElementById('modalCancelBtn').addEventListener('click', closeModal);
// Close modal when clicking outside the modal card
window.addEventListener('click', function(event) {
const modal = document.getElementById('submitModal');
if (event.target === modal) {
modal.style.display = 'none';
}
});
/* ─── Init ─── */
window.addEventListener('DOMContentLoaded', () => {
renderStats();
buildFilters();
setupSortControl();
renderFilteredViews();
});
</script>
</body>
</html>