FlameF0X commited on
Commit
6571286
Β·
verified Β·
1 Parent(s): e19a1ea

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +66 -46
index.html CHANGED
@@ -66,7 +66,6 @@
66
  .org { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
67
  .dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
68
  .num { font-variant-numeric: tabular-nums; }
69
- .best { color: var(--sage-ink); font-weight: 600; background: var(--sage-soft); }
70
  .muted { color: var(--muted); }
71
  .links a { color: var(--clay); text-decoration: none; font-size: 13px; margin-right: 12px; }
72
  .links a:hover { text-decoration: underline; }
@@ -174,17 +173,18 @@
174
  <tbody id="boardBody"></tbody>
175
  </table>
176
  </div>
177
- <div class="legend">EM = exact grid match. fmt = output parses as a grid. Overall = mean across MARC-1/2/3. pass@n &gt; EM means the model has latent rule inference it doesn't always land. Highlighted cells mark the best value in the current view.</div>
178
  </section>
179
 
180
  <!-- TIER TABS (MARC-1, MARC-2, MARC-3) -->
181
  <section id="view-tier" hidden>
182
-
183
  <div class="info-box">
184
- <b>Understanding the graphs:</b> Small models often fall back on statistical guessing rather than solving the rule.
185
  <ul>
186
  <li>The <b style="color:#e05e5e;">Red dashed line</b> is the mathematical random-guessing baseline.</li>
187
  <li>The <b style="color:#e0b25c;">Yellow dashed line</b> is <b>2Γ— the random baseline</b>. Scoring below this generally means the model is just guessing, or worse, copying the input.</li>
 
188
  </ul>
189
  </div>
190
 
@@ -410,6 +410,7 @@ const DEMO_DATA = { models: [
410
  const esc = s => String(s ?? "").replace(/[&<>"']/g, c => ({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]));
411
  const fmtPct = v => v == null ? "β€”" : (v * 100).toFixed(1) + "%";
412
  const fmtNum = v => Number.isInteger(v) ? String(v) : (+v).toFixed(3).replace(/\.?0+$/,"");
 
413
 
414
  function parseParams(s) {
415
  if (!s) return NaN;
@@ -461,6 +462,15 @@ function getFamily(name) {
461
  return match ? match[1] : base;
462
  }
463
 
 
 
 
 
 
 
 
 
 
464
  // ─── Sort ───────────────────────────────────────────────────────────────────
465
  function buildSortOptions() {
466
  const sel = document.getElementById("sortSel");
@@ -500,7 +510,7 @@ function buildOrgChips(elId, customOrg, onPick) {
500
  document.getElementById(elId).innerHTML =
501
  chip("all","All",models.length) +
502
  Object.keys(counts).sort().map(k => chip(k,k,counts[k])).join("");
503
-
504
  document.getElementById(elId).onclick = e => {
505
  const c = e.target.closest(".chip"); if (!c) return;
506
  onPick(c.dataset.org);
@@ -509,21 +519,11 @@ function buildOrgChips(elId, customOrg, onPick) {
509
 
510
  function renderTable(isTierTab, tierId = null) {
511
  const key = isTierTab ? "marc"+tierId : sortKeyForTab();
512
- const filterOrg = isTierTab ? org : org;
513
-
514
  const list = models
515
- .filter(m => (filterOrg === "all" || m.org === filterOrg) && (size === "all" || sizeOf(m.params) === size))
516
  .sort(SORTS[key]);
517
 
518
- const bestOverall = list.map(overallEm).filter(v => v != null);
519
- const bestTier = k => list.map(m => tierValue(m,k,"em")).filter(v => v != null);
520
- const bestFmt = list.map(overallFmt).filter(v => v != null);
521
- const bO = bestOverall.length ? Math.max(...bestOverall) : null;
522
- const b1 = bestTier("1").length ? Math.max(...bestTier("1")) : null;
523
- const b2 = bestTier("2").length ? Math.max(...bestTier("2")) : null;
524
- const b3 = bestTier("3").length ? Math.max(...bestTier("3")) : null;
525
- const bF = bestFmt.length ? Math.max(...bestFmt) : null;
526
-
527
  const countId = isTierTab ? "tierCount" : "count";
528
  const headId = isTierTab ? "tierHead" : "boardHead";
529
  const bodyId = isTierTab ? "tierBody" : "boardBody";
@@ -542,6 +542,9 @@ function renderTable(isTierTab, tierId = null) {
542
  <th>Links</th>
543
  </tr>`;
544
 
 
 
 
545
  document.getElementById(bodyId).innerHTML = list.length ? list.map((m,i) => {
546
  const c = orgColor[m.org] || "#888";
547
  const ov = overallEm(m), t1 = tierValue(m,"1","em"), t2 = tierValue(m,"2","em"), t3 = tierValue(m,"3","em"), f = overallFmt(m);
@@ -549,18 +552,17 @@ function renderTable(isTierTab, tierId = null) {
549
  if (m.links?.card) links.push(`<a href="${esc(m.links.card)}" target="_blank" rel="noopener">Card</a>`);
550
  if (m.links?.demo) links.push(`<a href="${esc(m.links.demo)}" target="_blank" rel="noopener">Demo</a>`);
551
  const mode = m.chat ? `<span class="mode chat">chat</span>` : `<span class="mode base">base</span>`;
552
- const cell = (v, best) => `<td class="r num ${v != null && v === best ? "best" : ""}">${v != null ? fmtPct(v) : '<span class="muted">β€”</span>'}</td>`;
553
  return `<tr>
554
  <td class="rank">${i+1}</td>
555
  <td class="name">${esc(m.name)}</td>
556
  <td><span class="org"><span class="dot" style="background:${c}"></span>${esc(m.org)}</span></td>
557
  <td class="num">${esc(m.params)}</td>
558
  <td>${mode}</td>
559
- ${cell(ov, bO)}
560
- ${cell(t1, b1)}
561
- ${cell(t2, b2)}
562
- ${cell(t3, b3)}
563
- <td class="r num ${f != null && f === bF ? "best" : ""}">${f != null ? fmtPct(f) : '<span class="muted">β€”</span>'}</td>
564
  <td class="links">${links.join("") || '<span class="muted">β€”</span>'}</td>
565
  </tr>`;
566
  }).join("") : `<tr><td colspan="11" class="empty">No models match these filters</td></tr>`;
@@ -576,7 +578,7 @@ const baselinePlugin = {
576
  if (!options || options.random === undefined) return;
577
  const { ctx, chartArea: { top, bottom, left, right }, scales: { y } } = chart;
578
  ctx.save();
579
-
580
  // Red line: 1x Random
581
  if (options.random > 0) {
582
  const y1 = y.getPixelForValue(options.random);
@@ -590,7 +592,7 @@ const baselinePlugin = {
590
  ctx.stroke();
591
  }
592
  }
593
-
594
  // Yellow line: 2x Random
595
  if (options.random > 0) {
596
  const y2 = y.getPixelForValue(options.random * 2);
@@ -604,6 +606,25 @@ const baselinePlugin = {
604
  ctx.stroke();
605
  }
606
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  ctx.restore();
608
  }
609
  };
@@ -612,19 +633,21 @@ Chart.register(baselinePlugin);
612
  function renderTierCharts(tierId) {
613
  tierChartInstances.forEach(c => c.destroy());
614
  tierChartInstances = [];
615
-
616
  const t = String(tierId);
 
617
 
618
  FAMILY_KEYS.forEach(fam => {
619
  // Group by family
620
  const groups = {};
621
  models.forEach(m => {
 
622
  const groupName = getFamily(m.name);
623
  if (!groups[groupName]) groups[groupName] = [];
624
-
625
  const p = parseParams(m.params);
626
  const emVal = m.families?.[fam]?.[t]?.em;
627
-
628
  if (!isNaN(p) && emVal != null) {
629
  groups[groupName].push({ x: p, y: emVal * 100, name: m.name, org: m.org });
630
  }
@@ -649,6 +672,8 @@ function renderTierCharts(tierId) {
649
  Chart.defaults.color = "#a29686";
650
  Chart.defaults.font.family = '"Avenir Next", "Segoe UI", system-ui, sans-serif';
651
 
 
 
652
  const inst = new Chart(document.getElementById(`tierChart-${fam}`), {
653
  type: "scatter",
654
  data: { datasets },
@@ -657,7 +682,10 @@ function renderTierCharts(tierId) {
657
  layout: { padding: { top: 10, right: 10 } },
658
  plugins: {
659
  legend: { display: false },
660
- baselines: { random: RANDOM_BASELINES[t][fam] },
 
 
 
661
  tooltip: { callbacks: { label: c => `${c.raw.name}: ${c.parsed.y.toFixed(1)}%` } }
662
  },
663
  scales: {
@@ -675,20 +703,12 @@ function renderTierCharts(tierId) {
675
  }
676
  }
677
  });
678
-
679
  tierChartInstances.push(inst);
680
  });
681
  }
682
 
683
  // ─── Families Heatmap ───────────────────────────────────────────────────────
684
- function heatColor(v) {
685
- if (v == null) return "transparent";
686
- const t = Math.max(0, Math.min(1, v));
687
- const lo = [74, 48, 38], hi = [45, 58, 47];
688
- const mix = lo.map((c, i) => Math.round(c + (hi[i] - c) * t));
689
- return `rgb(${mix[0]},${mix[1]},${mix[2]})`;
690
- }
691
-
692
  function renderFamilies() {
693
  const tierSel = document.getElementById("famTierSel").value;
694
  const sorted = [...models].sort((a,b) => (familyAvgEm(b, tierSel).avg ?? -1) - (familyAvgEm(a, tierSel).avg ?? -1));
@@ -789,12 +809,12 @@ function renderCharts() {
789
  function setTab(t) {
790
  currentTab = t;
791
  document.querySelectorAll(".tab").forEach(b => b.classList.toggle("on", b.dataset.tab === t));
792
-
793
  let viewId = "view-" + t;
794
  if (t === "marc1" || t === "marc2" || t === "marc3") {
795
  viewId = "view-tier";
796
  }
797
-
798
  document.querySelectorAll('[id^="view-"]').forEach(s => s.hidden = s.id !== viewId);
799
 
800
  if (t === "families") {
@@ -803,7 +823,8 @@ function setTab(t) {
803
  renderCharts();
804
  } else if (t === "marc1" || t === "marc2" || t === "marc3") {
805
  const tierId = t.replace("marc", "");
806
- buildOrgChips("tierOrgChips", org, (newOrg) => { org = newOrg; renderTable(true, tierId); buildOrgChips("tierOrgChips", org, (o)=>{org=o;renderTable(true,tierId);}); });
 
807
  renderTierCharts(tierId);
808
  renderTable(true, tierId);
809
  } else {
@@ -813,8 +834,6 @@ function setTab(t) {
813
  document.querySelectorAll(".tab").forEach(b => b.addEventListener("click", () => setTab(b.dataset.tab)));
814
 
815
  // ─── Filters ────────────────────────────────────────────────────────────────
816
- buildOrgChips("orgChips", org, (newOrg) => { org = newOrg; buildOrgChips("orgChips", org, (o)=>{org=o;renderTable(false);}); renderTable(false); });
817
-
818
  document.getElementById("sizeSel").addEventListener("change", e => { size = e.target.value; renderTable(false); });
819
  document.getElementById("sortSel").addEventListener("change", e => { sortKey = e.target.value; renderTable(false); });
820
  document.getElementById("famTierSel").addEventListener("change", () => renderFamilies());
@@ -864,10 +883,11 @@ async function init() {
864
  }
865
  const orgs = [...new Set(models.map(m => m.org))].sort();
866
  orgs.forEach((o, i) => orgColor[o] = PALETTE[i % PALETTE.length]);
867
-
868
  buildSortOptions();
869
- buildOrgChips("orgChips", org, (newOrg) => { org = newOrg; buildOrgChips("orgChips", org, (o)=>{org=o;renderTable(false);}); renderTable(false); });
870
-
 
871
  setTab("overall");
872
  }
873
  init();
 
66
  .org { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
67
  .dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
68
  .num { font-variant-numeric: tabular-nums; }
 
69
  .muted { color: var(--muted); }
70
  .links a { color: var(--clay); text-decoration: none; font-size: 13px; margin-right: 12px; }
71
  .links a:hover { text-decoration: underline; }
 
173
  <tbody id="boardBody"></tbody>
174
  </table>
175
  </div>
176
+ <div class="legend">EM = exact grid match. fmt = output parses as a grid. Overall = mean across MARC-1/2/3. pass@n &gt; EM means the model has latent rule inference it doesn't always land. Cell color scales from clay (low) to sage (high).</div>
177
  </section>
178
 
179
  <!-- TIER TABS (MARC-1, MARC-2, MARC-3) -->
180
  <section id="view-tier" hidden>
181
+
182
  <div class="info-box">
183
+ <b>Understanding the graphs:</b> Small models often fall back on statistical guessing rather than solving the rule.
184
  <ul>
185
  <li>The <b style="color:#e05e5e;">Red dashed line</b> is the mathematical random-guessing baseline.</li>
186
  <li>The <b style="color:#e0b25c;">Yellow dashed line</b> is <b>2Γ— the random baseline</b>. Scoring below this generally means the model is just guessing, or worse, copying the input.</li>
187
+ <li>The <b style="color:#8fb395;">Green dashed line</b> is the <b>average human</b> score for that family and tier.</li>
188
  </ul>
189
  </div>
190
 
 
410
  const esc = s => String(s ?? "").replace(/[&<>"']/g, c => ({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]));
411
  const fmtPct = v => v == null ? "β€”" : (v * 100).toFixed(1) + "%";
412
  const fmtNum = v => Number.isInteger(v) ? String(v) : (+v).toFixed(3).replace(/\.?0+$/,"");
413
+ const isHuman = m => /human/i.test(m?.name || "");
414
 
415
  function parseParams(s) {
416
  if (!s) return NaN;
 
462
  return match ? match[1] : base;
463
  }
464
 
465
+ // Red (low) -> green (high) heat color, shared by every table
466
+ function heatColor(v) {
467
+ if (v == null) return "transparent";
468
+ const t = Math.max(0, Math.min(1, v));
469
+ const lo = [74, 48, 38], hi = [45, 58, 47];
470
+ const mix = lo.map((c, i) => Math.round(c + (hi[i] - c) * t));
471
+ return `rgb(${mix[0]},${mix[1]},${mix[2]})`;
472
+ }
473
+
474
  // ─── Sort ───────────────────────────────────────────────────────────────────
475
  function buildSortOptions() {
476
  const sel = document.getElementById("sortSel");
 
510
  document.getElementById(elId).innerHTML =
511
  chip("all","All",models.length) +
512
  Object.keys(counts).sort().map(k => chip(k,k,counts[k])).join("");
513
+
514
  document.getElementById(elId).onclick = e => {
515
  const c = e.target.closest(".chip"); if (!c) return;
516
  onPick(c.dataset.org);
 
519
 
520
  function renderTable(isTierTab, tierId = null) {
521
  const key = isTierTab ? "marc"+tierId : sortKeyForTab();
522
+
 
523
  const list = models
524
+ .filter(m => (org === "all" || m.org === org) && (size === "all" || sizeOf(m.params) === size))
525
  .sort(SORTS[key]);
526
 
 
 
 
 
 
 
 
 
 
527
  const countId = isTierTab ? "tierCount" : "count";
528
  const headId = isTierTab ? "tierHead" : "boardHead";
529
  const bodyId = isTierTab ? "tierBody" : "boardBody";
 
542
  <th>Links</th>
543
  </tr>`;
544
 
545
+ // Heatmap cell: same red -> green gradient as the Families tab
546
+ const cell = v => `<td class="r num hm-cell" ${v != null ? `style="background:${heatColor(v)};color:var(--ink)"` : ""}>${v != null ? fmtPct(v) : '<span class="muted">β€”</span>'}</td>`;
547
+
548
  document.getElementById(bodyId).innerHTML = list.length ? list.map((m,i) => {
549
  const c = orgColor[m.org] || "#888";
550
  const ov = overallEm(m), t1 = tierValue(m,"1","em"), t2 = tierValue(m,"2","em"), t3 = tierValue(m,"3","em"), f = overallFmt(m);
 
552
  if (m.links?.card) links.push(`<a href="${esc(m.links.card)}" target="_blank" rel="noopener">Card</a>`);
553
  if (m.links?.demo) links.push(`<a href="${esc(m.links.demo)}" target="_blank" rel="noopener">Demo</a>`);
554
  const mode = m.chat ? `<span class="mode chat">chat</span>` : `<span class="mode base">base</span>`;
 
555
  return `<tr>
556
  <td class="rank">${i+1}</td>
557
  <td class="name">${esc(m.name)}</td>
558
  <td><span class="org"><span class="dot" style="background:${c}"></span>${esc(m.org)}</span></td>
559
  <td class="num">${esc(m.params)}</td>
560
  <td>${mode}</td>
561
+ ${cell(ov)}
562
+ ${cell(t1)}
563
+ ${cell(t2)}
564
+ ${cell(t3)}
565
+ ${cell(f)}
566
  <td class="links">${links.join("") || '<span class="muted">β€”</span>'}</td>
567
  </tr>`;
568
  }).join("") : `<tr><td colspan="11" class="empty">No models match these filters</td></tr>`;
 
578
  if (!options || options.random === undefined) return;
579
  const { ctx, chartArea: { top, bottom, left, right }, scales: { y } } = chart;
580
  ctx.save();
581
+
582
  // Red line: 1x Random
583
  if (options.random > 0) {
584
  const y1 = y.getPixelForValue(options.random);
 
592
  ctx.stroke();
593
  }
594
  }
595
+
596
  // Yellow line: 2x Random
597
  if (options.random > 0) {
598
  const y2 = y.getPixelForValue(options.random * 2);
 
606
  ctx.stroke();
607
  }
608
  }
609
+
610
+ // Green line: average human
611
+ if (options.human != null) {
612
+ const yh = y.getPixelForValue(options.human);
613
+ if (yh >= top && yh <= bottom) {
614
+ ctx.beginPath();
615
+ ctx.setLineDash([6, 4]);
616
+ ctx.lineWidth = 1.5;
617
+ ctx.strokeStyle = '#8fb395'; // sage green
618
+ ctx.moveTo(left, yh);
619
+ ctx.lineTo(right, yh);
620
+ ctx.stroke();
621
+ ctx.setLineDash([]);
622
+ ctx.fillStyle = '#8fb395';
623
+ ctx.font = '11px sans-serif';
624
+ ctx.textAlign = 'right';
625
+ ctx.fillText('Human ' + options.human.toFixed(0) + '%', right - 4, yh - 4);
626
+ }
627
+ }
628
  ctx.restore();
629
  }
630
  };
 
633
  function renderTierCharts(tierId) {
634
  tierChartInstances.forEach(c => c.destroy());
635
  tierChartInstances = [];
636
+
637
  const t = String(tierId);
638
+ const human = models.find(isHuman);
639
 
640
  FAMILY_KEYS.forEach(fam => {
641
  // Group by family
642
  const groups = {};
643
  models.forEach(m => {
644
+ if (isHuman(m)) return; // human is drawn as a dashed line instead
645
  const groupName = getFamily(m.name);
646
  if (!groups[groupName]) groups[groupName] = [];
647
+
648
  const p = parseParams(m.params);
649
  const emVal = m.families?.[fam]?.[t]?.em;
650
+
651
  if (!isNaN(p) && emVal != null) {
652
  groups[groupName].push({ x: p, y: emVal * 100, name: m.name, org: m.org });
653
  }
 
672
  Chart.defaults.color = "#a29686";
673
  Chart.defaults.font.family = '"Avenir Next", "Segoe UI", system-ui, sans-serif';
674
 
675
+ const humanEm = human?.families?.[fam]?.[t]?.em;
676
+
677
  const inst = new Chart(document.getElementById(`tierChart-${fam}`), {
678
  type: "scatter",
679
  data: { datasets },
 
682
  layout: { padding: { top: 10, right: 10 } },
683
  plugins: {
684
  legend: { display: false },
685
+ baselines: {
686
+ random: RANDOM_BASELINES[t][fam],
687
+ human: humanEm != null ? humanEm * 100 : null
688
+ },
689
  tooltip: { callbacks: { label: c => `${c.raw.name}: ${c.parsed.y.toFixed(1)}%` } }
690
  },
691
  scales: {
 
703
  }
704
  }
705
  });
706
+
707
  tierChartInstances.push(inst);
708
  });
709
  }
710
 
711
  // ─── Families Heatmap ───────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
712
  function renderFamilies() {
713
  const tierSel = document.getElementById("famTierSel").value;
714
  const sorted = [...models].sort((a,b) => (familyAvgEm(b, tierSel).avg ?? -1) - (familyAvgEm(a, tierSel).avg ?? -1));
 
809
  function setTab(t) {
810
  currentTab = t;
811
  document.querySelectorAll(".tab").forEach(b => b.classList.toggle("on", b.dataset.tab === t));
812
+
813
  let viewId = "view-" + t;
814
  if (t === "marc1" || t === "marc2" || t === "marc3") {
815
  viewId = "view-tier";
816
  }
817
+
818
  document.querySelectorAll('[id^="view-"]').forEach(s => s.hidden = s.id !== viewId);
819
 
820
  if (t === "families") {
 
823
  renderCharts();
824
  } else if (t === "marc1" || t === "marc2" || t === "marc3") {
825
  const tierId = t.replace("marc", "");
826
+ const pick = o => { org = o; buildOrgChips("tierOrgChips", org, pick); renderTable(true, tierId); };
827
+ buildOrgChips("tierOrgChips", org, pick);
828
  renderTierCharts(tierId);
829
  renderTable(true, tierId);
830
  } else {
 
834
  document.querySelectorAll(".tab").forEach(b => b.addEventListener("click", () => setTab(b.dataset.tab)));
835
 
836
  // ─── Filters ────────────────────────────────────────────────────────────────
 
 
837
  document.getElementById("sizeSel").addEventListener("change", e => { size = e.target.value; renderTable(false); });
838
  document.getElementById("sortSel").addEventListener("change", e => { sortKey = e.target.value; renderTable(false); });
839
  document.getElementById("famTierSel").addEventListener("change", () => renderFamilies());
 
883
  }
884
  const orgs = [...new Set(models.map(m => m.org))].sort();
885
  orgs.forEach((o, i) => orgColor[o] = PALETTE[i % PALETTE.length]);
886
+
887
  buildSortOptions();
888
+ const pickOverall = o => { org = o; buildOrgChips("orgChips", org, pickOverall); renderTable(false); };
889
+ buildOrgChips("orgChips", org, pickOverall);
890
+
891
  setTab("overall");
892
  }
893
  init();