ModsCodeMERGEBLE LLC Search Claude Code Mods

ModsCode / Gallery / Designs / Dumbbell chart

Dumbbell chart

p50 and p95 latency per API route on one scale: a thin link between two dots, values at both ends, the p95 dot red past the latency objective.

Dumbbell chartDumbbell chart
Compare · 380×240 · sample data
hooks/designs/dumbbell.mjs
// dumbbell: p50 and p95 latency for eight API routes in candle's look, sorted by p95 from the slowest.
// Each route is a 1px link at 35% ink between two dots on one shared scale from 0 to 700 ms, the round
// number just past the slowest p95 (640). The p50 dot is ink; the p95 dot turns DOWN only past the
// 300 ms objective, drawn as candle's dashed 35% reference line, so the eye finds the slow tails without
// reading a number. The values sit outside both ends and are dropped when they would touch the route
// name; where a value crosses the reference line, the line breaks around it instead of the value moving,
// because a moved value would no longer sit on its dot. Routes, p50 / p95 in ms: POST /messages 210 / 640, POST /tools/run 160 / 420, GET /search
// 120 / 360, POST /upload 190 / 290, POST /auth/token 80 / 240, GET /repos 58 / 170, GET /sessions 42 /
// 118, GET /usage 35 / 90. The count over the objective is counted from the rows. Sample data only.
const W = 380
const H = 240
const STAGE = '#FAF9F5'
const INK = '#141413'
const MUTED = '#73726C'
const DOWN = '#AB2B3F'
const FONT = "'Inter Tight','Segoe UI',system-ui,sans-serif"
const MONO = "ui-monospace,'Cascadia Mono',Consolas,monospace"
const X0 = 124 // 0 ms; the method and path sit in the column before it
const X1 = 352 // 700 ms; the p95 values run into the space after it
const MAX = 700
const SLO = 300
const ROW0 = 40
const ROW = 21
const R = 2
const PLOT = { top: 28, bottom: 196 }
const f = n => n.toFixed(1)

const ROUTES = [
  ['POST', '/messages', 210, 640],
  ['POST', '/tools/run', 160, 420],
  ['GET', '/search', 120, 360],
  ['POST', '/upload', 190, 290],
  ['POST', '/auth/token', 80, 240],
  ['GET', '/repos', 58, 170],
  ['GET', '/sessions', 42, 118],
  ['GET', '/usage', 35, 90],
].sort((a, b) => b[3] - a[3])
const OVER = ROUTES.filter(r => r[3] > SLO).length

const text = (x, y, s, { size = 9, fill = MUTED, anchor = 'start', font = FONT, opacity } = {}) =>
  `<text x="${f(x)}" y="${f(y)}"${anchor === 'start' ? '' : ` text-anchor="${anchor}"`} font-size="${size}" font-family="${font}" fill="${fill}"${opacity ? ` fill-opacity="${opacity}"` : ''}>${s}</text>`
const x = ms => X0 + (ms / MAX) * (X1 - X0)
const width10 = s => s.length * 5.6 * 1.1 // a 10px label's width with 10% slack

function draw() {
  const parts = [`<rect width="${W}" height="${H}" rx="4" fill="${STAGE}"/>`]
  for (const t of [0, 200, 400, 600]) {
    const tx = Math.round(x(t)) + 0.5
    parts.push(`<line x1="${f(tx)}" x2="${f(tx)}" y1="${PLOT.top}" y2="${PLOT.bottom}" stroke="${INK}" stroke-opacity="0.08" stroke-width="1"/>`)
    parts.push(`<line x1="${f(tx)}" x2="${f(tx)}" y1="${PLOT.bottom + 2}" y2="${PLOT.bottom + 6}" stroke="${MUTED}" stroke-width="1"/>`)
    parts.push(text(tx, PLOT.bottom + 16, String(t), { anchor: 'middle' }))
  }
  parts.push(text(W - 12, PLOT.bottom + 16, 'MS', { anchor: 'end' }))
  const sx = Math.round(x(SLO)) + 0.5
  const rows = []
  const gaps = [] // [top, bottom] spans where a value label sits on the reference line
  const label = (x0, x1, cy, svg) => {
    if (sx > x0 - 3 && sx < x1 + 3) gaps.push([cy - 7, cy + 7])
    rows.push(svg)
  }
  parts.push(text(12, 18, 'ROUTE'))
  parts.push(text(W - 12, 18, `${OVER} OVER ${SLO} MS`, { fill: DOWN, anchor: 'end' }))

  ROUTES.forEach(([method, path, p50, p95], i) => {
    const cy = ROW0 + i * ROW + 0.5 // on a pixel centre so the 1px link stays sharp
    const a = x(p50)
    const b = x(p95)
    const slow = p95 > SLO
    rows.push(text(12, cy + 3, method, { font: MONO }))
    rows.push(text(44, cy + 3.5, path, { size: 10, fill: INK, font: MONO }))
    rows.push(`<line x1="${f(a + R)}" x2="${f(b - R)}" y1="${f(cy)}" y2="${f(cy)}" stroke="${INK}" stroke-opacity="0.35" stroke-width="1"/>`)
    rows.push(`<circle cx="${f(a)}" cy="${f(cy)}" r="${R}" fill="${INK}"/>`)
    rows.push(`<circle cx="${f(b)}" cy="${f(cy)}" r="${R}" fill="${slow ? DOWN : INK}"${slow ? '' : ' fill-opacity="0.6"'}/>`)
    // The p50 value steps aside rather than touch the path; the p95 value stops at W - 12
    const nameEnd = 44 + path.length * 6 + 4
    const left = String(p50)
    if (a - R - 5 - width10(left) > nameEnd) label(a - R - 5 - left.length * 5.6, a - R - 5, cy, text(a - R - 5, cy + 3.5, left, { size: 10, fill: INK, anchor: 'end' }))
    const right = String(p95)
    if (b + R + 5 + width10(right) <= W - 12) label(b + R + 5, b + R + 5 + right.length * 5.6, cy, text(b + R + 5, cy + 3.5, right, { size: 10, fill: slow ? DOWN : INK, opacity: slow ? undefined : 0.6 }))
  })

  // The reference line goes under the rows, as one path with a break at each value it would cross;
  // breaks less than 9px apart join, since a lone dash between two values reads as a mark of its own
  let d = ''
  let top = PLOT.top - 4
  for (const [g0, g1] of gaps.sort((p, q) => p[0] - q[0])) {
    if (g0 > top + 9) d += `M${f(sx)} ${f(top)}V${f(g0)}`
    top = Math.max(top, g1)
  }
  if (PLOT.bottom > top) d += `M${f(sx)} ${f(top)}V${PLOT.bottom}`
  parts.push(`<path d="${d}" fill="none" stroke="${INK}" stroke-opacity="0.35" stroke-width="1" stroke-dasharray="3 3"/>`)
  parts.push(text(sx, 18, `SLO ${SLO} MS`, { anchor: 'middle' }))
  parts.push(...rows)

  parts.push(`<circle cx="${W - 66}" cy="${H - 11}" r="${R}" fill="${INK}"/>`)
  parts.push(text(W - 60, H - 8, 'P50'))
  parts.push(`<circle cx="${W - 32}" cy="${H - 11}" r="${R}" fill="${INK}" fill-opacity="0.6"/>`)
  parts.push(text(W - 26, H - 8, 'P95'))
  parts.push(text(12, H - 8, 'SAMPLE LATENCY BY ROUTE'))
  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: 'dumbbell',
  title: 'Dumbbell chart',
  category: 'compare',
  description: 'p50 and p95 latency per API route on one scale: a thin link between two dots, values at both ends, the p95 dot red past the latency objective.',
  element: ui => ui.Svg({ source: (source ??= draw()), alt: `Dumbbell chart of p50 and p95 latency for ${ROUTES.length} API routes against a ${SLO} ms objective, ${OVER} of them over it, 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).