← back to Model Arena
polish comparison and leaderboard workflows
92c23ba8c8d98de1df3a23dcbe6c8873eb9fc62e · 2026-08-31 12:44:46 -0700 · Steve Abrams
Files touched
M public/index.htmlA verification/ui-detail.pngA verification/ui-leaderboard.pngM verification/ui-redesign-proof.jsonA verification/ui-surfaces.e2e.js
Diff
commit 92c23ba8c8d98de1df3a23dcbe6c8873eb9fc62e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Aug 31 12:44:46 2026 -0700
polish comparison and leaderboard workflows
---
public/index.html | 12 +++++++++---
verification/ui-detail.png | Bin 0 -> 355332 bytes
verification/ui-leaderboard.png | Bin 0 -> 120831 bytes
verification/ui-redesign-proof.json | 13 +++++++++++++
verification/ui-surfaces.e2e.js | 31 +++++++++++++++++++++++++++++++
5 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/public/index.html b/public/index.html
index a0940e6..66a643e 100644
--- a/public/index.html
+++ b/public/index.html
@@ -233,6 +233,8 @@ input[type=range]{accent-color:var(--neon)}
.models{grid-template-columns:repeat(auto-fill,minmax(245px,1fr));gap:10px}.mrow{min-height:50px;border-color:#e0e4e9;border-radius:10px;background:#fafbfc;padding:10px 12px}.mrow.dtd{border-color:#cdd9ed;background:#f4f7fc}.mrow.off{filter:saturate(.2);opacity:.55}.mrow input{accent-color:#245dbf}.dtdb{border-color:#9db5de;border-radius:4px;color:#315f9f}.hfb{border-color:#c7a76a;color:#8c681f}.note{color:#7a8492;font-size:12px}.blindtog{color:#667286}.blindtog input{accent-color:#245dbf}
#f-go{min-width:150px;background:var(--navy);border-color:var(--navy);color:#fff;padding:12px 22px}
.back{color:#315f9f;font-family:"Avenir Next",sans-serif;font-weight:650}.arena{gap:20px}.pane{border:1px solid var(--line);border-radius:15px;background:#fff;box-shadow:0 2px 8px rgba(15,23,42,.05);overflow:hidden}.pane .bar{min-height:52px;padding:10px 14px;border-color:var(--line);background:#fbfcfd}.pane .bar .name{color:var(--ink)}.pane.winner{border-color:#d8b76f;box-shadow:0 0 0 3px rgba(214,174,90,.13),0 18px 42px rgba(15,23,42,.1)}.pane.winner .bar{background:#fff9ed}.pane iframe,.poster,.pane .msg{height:500px}.aibar{padding:12px 15px;border:1px solid #d7e0ee;border-left:3px solid #3d72c7;border-radius:10px;background:#f2f6fc;color:#526177}.aibar b,.aiscore{color:#244f91}.aireason{border-color:var(--line);background:#fbfcfd;color:#6e7887}
+.detail-actions{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:10px;padding:11px;border:1px solid var(--line);border-radius:13px;background:#fff;box-shadow:0 1px 3px rgba(15,23,42,.04)}
+.detail-actions .back{margin:0!important;padding:7px 8px}.detail-actions .btn{margin:0!important}.detail-actions #d-buildbar{display:flex;gap:7px;margin:0!important}.detail-actions #d-buildbar[hidden]{display:none}
table{border-collapse:separate;border-spacing:0;border:1px solid var(--line);border-radius:14px;background:#fff;overflow:hidden;box-shadow:0 2px 8px rgba(15,23,42,.035)}th{background:#f6f8fa;color:#6d7785;font-weight:800}th,td{padding:13px 14px;border-color:#e8ebef}tr.clk:hover td{background:#f3f7fd}tr.first td{color:#76501c;background:#fffbf2}
.gcard{border-color:var(--line);border-radius:14px;background:#fff;overflow:hidden;box-shadow:0 2px 8px rgba(15,23,42,.04)}.gcard:hover{border-color:#aab7c8}.gcard .gm .gt{color:var(--ink)}
.seed{border-color:var(--line);border-radius:9px;background:#fff}.champ{border-color:#d8b76f;border-radius:14px;background:#fff9ed;box-shadow:none}.srcview{background:#101827;color:#bcd0ed}
@@ -310,14 +312,16 @@ table{border-collapse:separate;border-spacing:0;border:1px solid var(--line);bor
</section>
<section id="detail" class="view">
+ <div class="detail-actions">
<span class="back" id="back">← back to challenges</span>
<a class="back" id="export" style="margin-left:16px" download>⬇ export battle as standalone HTML</a>
<button class="btn pink" id="rerun-all" style="margin-left:16px" title="Re-run EVERY model in this battle from scratch (re-spends any metered models)">↻ Re-run entire challenge</button>
- <span id="d-buildbar" style="margin-left:16px;display:none">
+ <span id="d-buildbar" hidden>
<select id="d-build-pick" class="btn" title="Pick which model's artifact to build inside an iTerm2 Claude session"></select>
<button class="btn pink" id="d-build-go" title="Open an iTerm2 Claude session and build the selected model's artifact into a real project">⚒ Build in iTerm2</button>
</span>
<button class="btn" id="d-continue" style="margin-left:16px" title="Start another battle — jump to the New Battle form">⚔ Continue with battles</button>
+ </div>
<label class="blindtog"><input type="checkbox" id="blind"> 🕶 Blind judging — hide model names until a winner is crowned (kills brand bias)</label>
<h2 id="d-title"></h2>
<div class="meta" id="d-meta"></div>
@@ -386,6 +390,8 @@ function show(view){
$('#'+view).classList.add('on');
const nb = $('#nav-'+view); if (nb) nb.classList.add('on');
if (view!=='detail' && pollTimer){ clearInterval(pollTimer); pollTimer=null; }
+ document.documentElement.scrollTop=0; document.body.scrollTop=0;
+ requestAnimationFrame(()=>window.scrollTo(0,0));
}
$('#nav-challenges').onclick = ()=>{ show('challenges'); loadList(); };
$('#nav-new').onclick = ()=>show('new');
@@ -557,11 +563,11 @@ async function renderDetail(id, statusOnly){
const bbar=$('#d-buildbar'), bpick=$('#d-build-pick'), bgo=$('#d-build-go');
if (bbar){
if (doneRuns.length){
- bbar.style.display='';
+ bbar.hidden=false;
const def = c.winner || c.aiPick || doneRuns[0].model;
bpick.innerHTML = doneRuns.map(r=>`<option value="${r.model}"${r.model===def?' selected':''}>${mLabel(r.model)}${r.model===c.winner?' 👑':(r.model===c.aiPick?' 🤖':'')}</option>`).join('');
bgo.onclick = ()=> buildInIterm(current.id, bgo, bpick.value);
- } else { bbar.style.display='none'; }
+ } else { bbar.hidden=true; }
}
// Continue with battles — jump to the New Battle form (mirrors the + New Battle nav)
{ const cont=$('#d-continue'); if (cont) cont.onclick = ()=> show('new'); }
diff --git a/verification/ui-detail.png b/verification/ui-detail.png
new file mode 100644
index 0000000..8749a68
Binary files /dev/null and b/verification/ui-detail.png differ
diff --git a/verification/ui-leaderboard.png b/verification/ui-leaderboard.png
new file mode 100644
index 0000000..fe0f97d
Binary files /dev/null and b/verification/ui-leaderboard.png differ
diff --git a/verification/ui-redesign-proof.json b/verification/ui-redesign-proof.json
index 757399d..b40e3c7 100644
--- a/verification/ui-redesign-proof.json
+++ b/verification/ui-redesign-proof.json
@@ -29,6 +29,19 @@
"assertions": ["hero CTA opens New Battle", "six DTD badges", "single/DTD/all/clear selection", "selection persistence after reload", "zero actionable console or page errors"],
"verdict": "PASS"
},
+ {
+ "boundary": "battle comparison workspace",
+ "command": "ARENA_URL=http://127.0.0.1:19759/ node verification/ui-surfaces.e2e.js",
+ "artifact": "verification/ui-detail.png",
+ "assertions": ["real battle opens from card", "four comparison panes render", "AI-referee panel is legible", "battle actions are grouped in a responsive command row"],
+ "verdict": "PASS"
+ },
+ {
+ "boundary": "leaderboard workspace",
+ "artifact": "verification/ui-leaderboard.png",
+ "assertions": ["11 model rows render", "navigation resets scroll position to zero", "ranking hierarchy and table density remain readable"],
+ "verdict": "PASS"
+ },
{
"boundary": "regression",
"commands": ["node --test verification/daily-novelty.test.js", "node --check server.js", "node --check scripts/daily-challenge.js", "git diff --check"],
diff --git a/verification/ui-surfaces.e2e.js b/verification/ui-surfaces.e2e.js
new file mode 100644
index 0000000..311fb63
--- /dev/null
+++ b/verification/ui-surfaces.e2e.js
@@ -0,0 +1,31 @@
+#!/usr/bin/env node
+const { chromium } = require('/Users/macstudio3/Projects/Designer-Wallcoverings/node_modules/playwright');
+
+(async () => {
+ const url = process.env.ARENA_URL || 'http://127.0.0.1:19759/';
+ const browser = await chromium.launch({ executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', headless: true });
+ const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } });
+ const page = await context.newPage();
+ const errors = [], bad = [];
+ page.on('pageerror', e => errors.push(String(e)));
+ page.on('console', m => { if (m.type() === 'error' && !/^Failed to load resource:/.test(m.text())) errors.push(m.text()); });
+ page.on('response', r => { if (r.status() >= 400 && !/\/(thumb|artifact)\//.test(r.url())) bad.push(`${r.status()} ${r.url()}`); });
+
+ await page.goto(url, { waitUntil: 'load' });
+ await page.waitForSelector('#list .card');
+ await page.locator('#list .card').first().click();
+ await page.waitForSelector('#detail.view.on .pane');
+ if (await page.locator('#d-title').textContent() === '') throw new Error('detail title missing');
+ if (await page.locator('#detail .pane').count() < 1) throw new Error('comparison panes missing');
+ await page.screenshot({ path: 'verification/ui-detail.png' });
+
+ await page.click('#nav-board');
+ await page.waitForSelector('#b-rows tr');
+ await page.waitForFunction(() => window.scrollY === 0);
+ if (await page.locator('#b-rows tr').count() < 1) throw new Error('leaderboard rows missing');
+ await page.screenshot({ path: 'verification/ui-leaderboard.png' });
+
+ if (errors.length || bad.length) throw new Error(`errors: ${errors.join(' | ')} ${bad.join(' | ')}`);
+ console.log(JSON.stringify({ pass: true, comparisonPanes: await page.locator('#detail .pane').count(), leaderboardRows: await page.locator('#b-rows tr').count(), errors: 0 }));
+ await browser.close();
+})().catch(e => { console.error(e.stack || e); process.exit(1); });
← 9152be0 snapshot generated arena artifacts before UI verification
·
back to Model Arena
·
snapshot generated Claude arena landing 256567e →