ModsCodeMERGEBLE LLC Search Claude Code Mods

ModsCode / Gallery / Designs / Progress rings

Progress rings

Four full rings in a row, each a 2px arc over a faint track with the percent in the centre; a ring that is full turns green.

Progress ringsProgress rings
Usage and limits · 380×144 · sample data
hooks/designs/progress-rings.mjs
// progress-rings: four full rings in a row in candle's look, each in a quarter of the width. The value
// arc is 2px (the one stroke whose colour must carry) and starts at 12 o'clock going clockwise over a
// track of the same width at 14% ink (the ladder's track step), so no track shows past the arc's
// edges. The percent sits in the centre at 13px, the name and the raw count under the ring. A ring that is full turns UP, arc and
// number together, as gauge does with its threshold colour; the others stay ink. The four samples are
// exact ratios: 164k of 200k tokens (82%), 16 of 25 tasks (64%), $14.80 of $40 (37%), 412 of 412
// tests (100%). Sample data only.
const W = 380
const H = 144
const STAGE = '#FAF9F5'
const INK = '#141413'
const MUTED = '#73726C'
const UP = '#2C7A39'
const FONT = "'Inter Tight','Segoe UI',system-ui,sans-serif"
const R = 30
const CY = 54
const CELL = W / 4
const f = n => n.toFixed(1)

const RINGS = [
  { name: 'Context', detail: '164k / 200k', value: 0.82 },
  { name: 'Tasks', detail: '16 / 25', value: 0.64 },
  { name: 'Budget', detail: '$14.80 / $40', value: 0.37 },
  { name: 'Tests', detail: '412 / 412', value: 1 },
]

const text = (x, y, s, { size = 9, fill = MUTED } = {}) =>
  `<text x="${f(x)}" y="${f(y)}" text-anchor="middle" font-size="${size}" font-family="${FONT}" fill="${fill}">${s}</text>`

// A point on the ring at fraction v of a turn, measured clockwise from 12 o'clock
const at = (cx, v) => {
  const a = -Math.PI / 2 + 2 * Math.PI * v
  return `${f(cx + R * Math.cos(a))} ${f(CY + R * Math.sin(a))}`
}

function ring(r, i) {
  const cx = CELL / 2 + i * CELL
  const full = r.value >= 1
  const color = full ? UP : INK
  const parts = [`<circle cx="${f(cx)}" cy="${CY}" r="${R}" fill="none" stroke="${INK}" stroke-opacity="0.14" stroke-width="2"/>`]
  // An arc from a point back to itself draws nothing, so a full ring is a circle
  if (full) parts.push(`<circle cx="${f(cx)}" cy="${CY}" r="${R}" fill="none" stroke="${color}" stroke-width="2"/>`)
  else parts.push(`<path d="M${at(cx, 0)} A${R} ${R} 0 ${r.value > 0.5 ? 1 : 0} 1 ${at(cx, r.value)}" fill="none" stroke="${color}" stroke-width="2"/>`)
  parts.push(text(cx, CY + 4.5, `${Math.round(r.value * 100)}%`, { size: 13, fill: color }))
  parts.push(text(cx, CY + R + 18, r.name, { size: 10, fill: INK }))
  parts.push(text(cx, CY + R + 31, r.detail))
  return parts.join('')
}

function draw() {
  const parts = [`<rect width="${W}" height="${H}" rx="4" fill="${STAGE}"/>`]
  RINGS.forEach((r, i) => parts.push(ring(r, i)))
  parts.push(`<text x="12" y="${H - 8}" font-size="9" font-family="${FONT}" fill="${MUTED}">SAMPLE SESSION PROGRESS</text>`)
  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: 'progress-rings',
  title: 'Progress rings',
  category: 'usage',
  description: 'Four full rings in a row, each a 2px arc over a faint track with the percent in the centre; a ring that is full turns green.',
  element: ui => ui.Svg({ source: (source ??= draw()), alt: 'Four progress rings for context, tasks, budget and tests at 82, 64, 37 and 100 percent, 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).