ModsCode / Gallery / Designs / Lollipop chart
Lollipop chart
The top ten repos by tokens, sorted: a thin stem and a dot for each, values on the right, and the top repo in Claude orange.


hooks/designs/lollipop.mjs
// lollipop: the top ten repos by tokens over seven days in candle's look, sorted from the most down.
// Each row is a 1px stem at 35% ink (candle's reference-line weight) from one shared zero edge to a
// dot of r=3, so the length reads like a bar's without a bar's weight; the value sits right-aligned at
// W - 12. The top item is the one Claude orange on the sheet. The scale ends at 2.5M, a round number just past
// the largest value. Tokens in millions: 2.41, 1.86, 1.52, 1.17, 0.94, 0.71, 0.58, 0.42, 0.27, 0.15
// (10.03 in all). Sample data only.
const W = 380
const H = 250
const STAGE = '#FAF9F5'
const INK = '#141413'
const MUTED = '#73726C'
const CLAUDE = '#D77757'
const FONT = "'Inter Tight','Segoe UI',system-ui,sans-serif"
const MONO = "ui-monospace,'Cascadia Mono',Consolas,monospace"
const X0 = 120 // the shared zero edge of every stem; rank and name sit before it
const X1 = 320 // where the scale end (2.5M) lands; the values sit after it
const SCALE = 2.5
const ROW0 = 38
const ROW = 20
const f = n => n.toFixed(1)
const REPOS = [
['api-server', 2.41], ['web-app', 1.86], ['cli', 1.52], ['infra', 1.17], ['billing', 0.94],
['docs', 0.71], ['auth', 0.58], ['search', 0.42], ['mobile', 0.27], ['design-system', 0.15],
].sort((a, b) => b[1] - a[1])
const text = (x, y, s, { size = 9, fill = MUTED, anchor = 'start', font = FONT } = {}) =>
`<text x="${f(x)}" y="${f(y)}"${anchor === 'start' ? '' : ` text-anchor="${anchor}"`} font-size="${size}" font-family="${font}" fill="${fill}">${s}</text>`
function draw() {
const parts = [`<rect width="${W}" height="${H}" rx="4" fill="${STAGE}"/>`]
parts.push(text(32, 18, 'REPO'))
parts.push(text(W - 12, 18, 'TOKENS, 7 DAYS', { anchor: 'end' }))
REPOS.forEach(([name, v], i) => {
const cy = ROW0 + i * ROW + 0.5 // on a pixel centre so the 1px stem stays sharp
const cx = X0 + (v / SCALE) * (X1 - X0)
const top = i === 0
const color = top ? CLAUDE : INK
parts.push(text(24, cy + 3, String(i + 1), { anchor: 'end', font: MONO }))
parts.push(text(32, cy + 3.5, name, { size: 10, fill: INK }))
parts.push(`<line x1="${X0}" x2="${f(cx - 3)}" y1="${f(cy)}" y2="${f(cy)}" stroke="${color}" stroke-opacity="${top ? 0.85 : 0.35}" stroke-width="1"/>`)
parts.push(`<circle cx="${f(cx)}" cy="${f(cy)}" r="3" fill="${color}"${top ? '' : ' fill-opacity="0.9"'}/>`)
parts.push(text(W - 12, cy + 4, `${v.toFixed(2)}M`, { size: 11, fill: top ? CLAUDE : INK, anchor: 'end' }))
})
const total = REPOS.reduce((s, r) => s + r[1], 0)
parts.push(text(W - 12, H - 8, `TOTAL ${total.toFixed(2)}M`, { anchor: 'end' }))
parts.push(text(12, H - 8, 'SAMPLE TOP 10 REPOS'))
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">${parts.join('')}</svg>`
}
let source // drawn on first use and kept: the pane loads every design, so none pays at load time
export default {
id: 'lollipop',
title: 'Lollipop chart',
category: 'compare',
description: 'The top ten repos by tokens, sorted: a thin stem and a dot for each, values on the right, and the top repo in Claude orange.',
element: ui => ui.Svg({ source: (source ??= draw()), alt: 'Lollipop chart of the top ten repos by tokens over seven days, the largest in Claude orange, sample data', width: W, height: H }),
}
To use it in a mod: copy the file to your mod's hooks/designs/ and return its element(ui) from a pane's ui.render. How a pane is built.
Code: PolyForm Noncommercial License 1.0.0: noncommercial use only. Required Notice: Copyright 2026 Haruki Nakada (https://modscode.com).