ModsCodeMERGEBLE LLC Search Claude Code Mods

ModsCode / Gallery / Designs / Context window meter

Context window meter

One stacked bar of the context window split into system, tools, MCP, memory and messages, with free space hollow and the autocompact line.

Context window meterContext window meter
Usage and limits · 380×120 · sample data
hooks/designs/context-window.mjs
// context-window: one session's 200K context window as a single stacked bar, in candle's look. The
// sample is a working session: system prompt 3.1K, tools 14.2K, MCP tools 9.6K, memory files 6.8K and
// messages 98.4K, so 132.1K is used (66%) and 67.9K is free. The four fixed parts take the ink steps
// 0.9 / 0.65 / 0.42 / 0.22 and messages, the only part the person can clear, takes the one Claude orange at the
// body strength 0.55, not 0.9: it is half the bar, and a full-strength slab that wide would out-shout
// every other mark. Free space is a hollow outline so it never reads as a fifth fill. Autocompact at 80% (160K) is a dashed
// reference line at 35% ink, labelled with the 27.9K left before it fires. Segments sit 1px apart and
// every value is in the legend, since the small parts are too narrow to carry their own label.
// Sample data only.
const W = 380
const H = 120
const STAGE = '#FAF9F5'
const INK = '#141413'
const MUTED = '#73726C'
const CLAUDE = '#D77757'
const FONT = "'Inter Tight','Segoe UI',system-ui,sans-serif"
const BAR = { left: 12, right: 368, top: 40, height: 14 }
const GAP = 1 // px of stage between two segments
const WINDOW = 200000
const AUTOCOMPACT = 0.8
const PARTS = [
  { name: 'System', tokens: 3100, fill: INK, opacity: 0.9 },
  { name: 'Tools', tokens: 14200, fill: INK, opacity: 0.65 },
  { name: 'MCP', tokens: 9600, fill: INK, opacity: 0.42 },
  { name: 'Memory', tokens: 6800, fill: INK, opacity: 0.22 },
  { name: 'Messages', tokens: 98400, fill: CLAUDE, opacity: 0.55 },
]
const f = n => n.toFixed(1)
const k = v => (v / 1000).toFixed(1) + 'K'
const text = (x, y, s, { size = 9, fill = MUTED, anchor = 'start' } = {}) =>
  `<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 used = PARTS.reduce((s, p) => s + p.tokens, 0)
  const free = WINDOW - used
  const span = BAR.right - BAR.left
  const x = t => BAR.left + (span * t) / WINDOW
  const yb = BAR.top + BAR.height
  const parts = [`<rect width="${W}" height="${H}" rx="4" fill="${STAGE}"/>`]

  parts.push(text(12, 28, Math.round((used / WINDOW) * 100) + '%', { size: 18, fill: INK }))
  parts.push(text(54, 28, `${k(used)} OF ${WINDOW / 1000}K TOKENS`))

  // Used parts left to right; half the gap comes off each side of every edge between two segments
  let at = 0
  for (const p of PARTS) {
    const x0 = x(at) + (at ? GAP / 2 : 0)
    const x1 = x(at + p.tokens) - GAP / 2
    parts.push(`<rect x="${f(x0)}" y="${BAR.top}" width="${f(x1 - x0)}" height="${BAR.height}" fill="${p.fill}" fill-opacity="${p.opacity}"/>`)
    at += p.tokens
  }
  // Free space: an outline inset half a pixel so its 1px stroke lands on whole pixels
  const fx = x(at) + GAP / 2 + 0.5
  parts.push(`<rect x="${f(fx)}" y="${BAR.top + 0.5}" width="${f(BAR.right - 0.5 - fx)}" height="${BAR.height - 1}" fill="none" stroke="${INK}" stroke-opacity="0.18"/>`)

  // Autocompact: a reference line that reaches 6px past the bar, its label above
  const ax = x(WINDOW * AUTOCOMPACT)
  parts.push(`<line x1="${f(ax)}" x2="${f(ax)}" y1="${BAR.top - 6}" y2="${yb + 6}" stroke="${INK}" stroke-opacity="0.35" stroke-dasharray="3 3"/>`)
  parts.push(text(ax, 28, `AUTOCOMPACT IN ${k(WINDOW * AUTOCOMPACT - used)}`, { anchor: 'middle' }))

  // Legend: three columns, two rows, every part with its tokens; free is the hollow swatch
  const rows = [...PARTS, { name: 'Free', tokens: free }]
  const colW = (span - 32) / 3
  rows.forEach((p, i) => {
    const cx = BAR.left + (i % 3) * (colW + 16)
    const ly = i < 3 ? 80 : 96
    parts.push(p.fill
      ? `<rect x="${f(cx)}" y="${ly - 7}" width="6" height="6" fill="${p.fill}" fill-opacity="${p.opacity}"/>`
      : `<rect x="${f(cx + 0.5)}" y="${ly - 6.5}" width="5" height="5" fill="none" stroke="${INK}" stroke-opacity="0.35"/>`)
    parts.push(text(cx + 14, ly, p.name, { size: 11, fill: INK }))
    parts.push(text(cx + colW, ly, k(p.tokens), { size: 11, fill: INK, anchor: 'end' }))
  })
  parts.push(text(12, H - 8, 'SAMPLE SESSION CONTEXT'))
  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: 'context-window',
  title: 'Context window meter',
  category: 'usage',
  description: 'One stacked bar of the context window split into system, tools, MCP, memory and messages, with free space hollow and the autocompact line.',
  element: ui => ui.Svg({ source: (source ??= draw()), alt: 'Stacked bar of the context window by part, with free space, the autocompact line and a legend of token counts, 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).