← back to Model Arena
arena: cost dashboard across top (today/week/month/year/all-time)
595106f7488b0798ebcc6f8f294b688b6a7aeee8 · 2026-07-23 12:17:24 -0700 · Steve
Files touched
M public/index.htmlM server.js
Diff
commit 595106f7488b0798ebcc6f8f294b688b6a7aeee8
Author: Steve <steve@designerwallcoverings.com>
Date: Thu Jul 23 12:17:24 2026 -0700
arena: cost dashboard across top (today/week/month/year/all-time)
---
public/index.html | 21 +++++++++++++++++++++
server.js | 23 +++++++++++++++++++++++
2 files changed, 44 insertions(+)
diff --git a/public/index.html b/public/index.html
index 86d7e64..dac9e3d 100644
--- a/public/index.html
+++ b/public/index.html
@@ -143,6 +143,10 @@ tr.clk{cursor:pointer}tr.clk:hover td{background:rgba(0,229,255,.06)}
.champ{border:1px solid var(--gold);background:rgba(255,199,46,.08);padding:14px 18px;text-align:center;box-shadow:0 0 22px rgba(255,199,46,.25)}
.champ .k{font-size:26px}.champ b{color:var(--gold);font-size:16px}
.pane .buildbtm{display:block;width:100%;margin-top:8px;padding:10px;font-weight:700;letter-spacing:1px;border-radius:4px;cursor:pointer}
+.costbar{position:sticky;top:0;z-index:4;display:flex;gap:20px;align-items:center;flex-wrap:wrap;background:rgba(9,10,18,.96);backdrop-filter:blur(6px);border-bottom:1px solid var(--line);padding:9px 22px;font-size:12px}
+.costbar .cb-lbl{color:var(--gold);letter-spacing:1px;text-transform:uppercase;font-size:11px}
+.costbar .cb-item{color:var(--dim)}.costbar .cb-item b{color:var(--txt);margin-left:5px;font-weight:700}
+.costbar .cb-item b.hot{color:var(--gold)}
</style>
</head>
<body>
@@ -155,6 +159,14 @@ tr.clk{cursor:pointer}tr.clk:hover td{background:rgba(0,229,255,.06)}
<button id="nav-board">Leaderboard</button>
</nav>
</header>
+<div class="costbar" id="costbar" title="Total metered API spend across the arena (local models + Claude Max CLI are $0)">
+ <span class="cb-lbl">💸 Arena spend</span>
+ <span class="cb-item">Today <b id="cb-today">$0</b></span>
+ <span class="cb-item">Week <b id="cb-week">$0</b></span>
+ <span class="cb-item">Month <b id="cb-month">$0</b></span>
+ <span class="cb-item">Year <b id="cb-year">$0</b></span>
+ <span class="cb-item">All-time <b id="cb-all">$0</b></span>
+</div>
<main>
<section id="challenges" class="view on">
<div class="controls">
@@ -621,6 +633,15 @@ function renderH2H(d){
}
loadModels().then(loadList);
+
+async function loadCosts(){
+ try{ const c=await (await fetch(API+'/api/costs')).json();
+ const f=n=>'$'+(Number(n)||0).toFixed(2);
+ const set=(id,v)=>{const e=document.getElementById(id); if(e){e.textContent=f(v); e.classList.toggle('hot',(Number(v)||0)>0);}};
+ set('cb-today',c.today); set('cb-week',c.week); set('cb-month',c.month); set('cb-year',c.year); set('cb-all',c.all);
+ }catch(e){}
+}
+loadCosts(); setInterval(loadCosts, 30000);
</script>
</body>
</html>
diff --git a/server.js b/server.js
index 9d8881a..cc09fe0 100644
--- a/server.js
+++ b/server.js
@@ -779,6 +779,29 @@ end tell`;
return send(res, 200, { model: { id: mid, label: mo.label, kind: mo.kind }, stats: full, gallery });
}
+ if (p === '/api/costs') {
+ const now = new Date();
+ const sDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
+ const dow = (now.getDay() + 6) % 7;
+ const sWeek = new Date(now.getFullYear(), now.getMonth(), now.getDate() - dow).getTime();
+ const sMonth = new Date(now.getFullYear(), now.getMonth(), 1).getTime();
+ const sYear = new Date(now.getFullYear(), 0, 1).getTime();
+ let today = 0, week = 0, month = 0, year = 0, all = 0;
+ try {
+ for (const line of fs.readFileSync(COST_FILE, 'utf8').split('\n')) {
+ if (!line.trim()) continue;
+ let d; try { d = JSON.parse(line); } catch { continue; }
+ const cst = d.cost_usd || 0; if (!cst) continue;
+ all += cst;
+ const t = Date.parse(d.ts || ''); if (isNaN(t)) continue;
+ if (t >= sYear) year += cst;
+ if (t >= sMonth) month += cst;
+ if (t >= sWeek) week += cst;
+ if (t >= sDay) today += cst;
+ }
+ } catch {}
+ return send(res, 200, { today, week, month, year, all });
+ }
if (p === '/api/ledger') {
const cat = u.searchParams.get('category') || '';
const l = buildLedger(cat || null);
← d6dfe90 auto-save: 2026-07-23T11:50:46 (15 files) — data/challenges.
·
back to Model Arena
·
auto-save: 2026-07-23T12:20:57 (15 files) — data/challenges. 34b99c1 →