ModsCodeMERGEBLE LLC Search Claude Code Mods

ModsCode / Gallery / Designs / Chord diagram

Chord diagram

Handoffs between agents around a ring: ribbon width by handoffs each way, with the busiest pair in Claude orange and its count.

Chord diagramChord diagram
Flows and links · 380×320 · sample data
hooks/designs/chord.mjs
// chord: a week of handoffs between six agents of a multi-agent Claude Code run, from a 6 x 6 matrix
// (row hands work to column, 317 handoffs in all, none to itself). The layout is d3-chord's chord()
// with a 0.04 rad gap between agents and each agent's ribbons sorted largest first, the ring is
// d3-shape's arc() and the ribbons d3-chord's ribbon() (all ISC, Mike Bostock). Ribbons are an 8% ink
// fill with a 1px edge at 22%, so the crossings read as lines, the way candle reads as wicks: the
// ribbons cover the whole disc, and a 25% fill, then a 14% fill with 35% edges, each turned it into a
// grey plate brighter than candle. The ring is a 6px band at candle's 55% body. Coder and Reviewer swap
// work most (42 + 34 = 76 handoffs), the review loop, and that one ribbon is Claude orange with its count
// written inside its wide Coder end (a one-entry key was dropped for that); the arcs stay ink, so Claude orange
// marks one pair only. Each name sits outside the ring, anchored away from it by the side it is on,
// with the handoffs that agent sent. Sample data only.
import { chord, ribbon, arc } from '../vendor/d3.mjs'

const W = 380
const H = 320
const STAGE = '#FAF9F5'
const INK = '#141413'
const MUTED = '#73726C'
const CLAUDE = '#D77757'
const FONT = "'Inter Tight','Segoe UI',system-ui,sans-serif"
const CX = 190
const CY = 156
const R_IN = 104
const R_OUT = 110
const AGENTS = ['Planner', 'Coder', 'Reviewer', 'Tester', 'Docs', 'Researcher']
// MATRIX[i][j]: handoffs from agent i to agent j in the week
const MATRIX = [
  [0, 38, 6, 8, 5, 22],
  [10, 0, 42, 30, 9, 6],
  [4, 34, 0, 8, 3, 2],
  [3, 26, 5, 0, 2, 1],
  [2, 4, 6, 1, 0, 3],
  [18, 12, 1, 2, 4, 0],
]
const PAIR = [1, 2] // Coder and Reviewer: the one Claude orange ribbon
const f = n => n.toFixed(1)
// ribbon() has no digits(), so its path is rounded here to one decimal
const round = d => d.replace(/-?\d+\.\d+(?:e-?\d+)?|-?\d+e-?\d+/g, m => Number(m).toFixed(1))

const esc = s => String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
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}">${esc(s)}</text>`

function draw() {
  const chords = chord().padAngle(0.04).sortSubgroups((a, b) => b - a)(MATRIX)
  const ring = arc().innerRadius(R_IN).outerRadius(R_OUT).digits(1)
  const band = ribbon().radius(R_IN - 1)
  const parts = [`<rect width="${W}" height="${H}" rx="4" fill="${STAGE}"/>`]
  parts.push(`<g transform="translate(${CX} ${CY})">`)

  const isPair = c => (c.source.index === PAIR[0] && c.target.index === PAIR[1]) || (c.source.index === PAIR[1] && c.target.index === PAIR[0])
  for (const c of [...chords].sort((a, b) => isPair(a) - isPair(b))) {
    const look = isPair(c) ? `fill="${CLAUDE}" fill-opacity="0.55"` : `fill="${INK}" fill-opacity="0.08"`
    parts.push(`<path d="${round(band(c))}" ${look} stroke="${isPair(c) ? CLAUDE : INK}" stroke-opacity="0.22"/>`)
  }
  for (const g of chords.groups) parts.push(`<path d="${ring(g)}" fill="${INK}" fill-opacity="0.55"/>`)
  parts.push('</g>')

  // Names outside the ring at the middle of each arc: anchored away from the ring by side, and pushed a
  // little further at the top and bottom, where the text runs along the ring instead of away from it
  for (const g of chords.groups) {
    const a = (g.startAngle + g.endAngle) / 2 // 0 at 12 o'clock, clockwise
    const sx = Math.sin(a)
    const cy = -Math.cos(a)
    const r = R_OUT + 8
    const x = CX + r * sx
    const y = CY + r * cy + 3.5 + cy * 6
    const anchor = Math.abs(sx) < 0.2 ? 'middle' : sx > 0 ? 'start' : 'end'
    const sent = MATRIX[g.index].reduce((s, v) => s + v, 0)
    parts.push(`<text x="${f(x)}" y="${f(y)}"${anchor === 'start' ? '' : ` text-anchor="${anchor}"`} font-size="10" font-family="${FONT}" fill="${INK}">${esc(AGENTS[g.index])}<tspan font-size="9" fill="${MUTED}"> ${sent}</tspan></text>`)
  }

  // The Claude orange ribbon carries its own count, both ways together, inside its wide end at the first agent
  // of the pair, where no other ribbon crosses it (a one-entry key below was dropped for this)
  const [p, q] = PAIR
  const hot = chords.find(isPair)
  const end = hot.source.index === p ? hot.source : hot.target
  const a = (end.startAngle + end.endAngle) / 2
  const r = R_IN * 0.78
  parts.push(text(CX + r * Math.sin(a), CY - r * Math.cos(a) + 3.5, MATRIX[p][q] + MATRIX[q][p], { size: 10, fill: INK, anchor: 'middle' }))
  const total = MATRIX.flat().reduce((s, v) => s + v, 0)
  parts.push(text(W - 12, H - 8, `TOTAL ${total}`, { anchor: 'end' }))
  parts.push(text(12, H - 8, 'SAMPLE HANDOFFS IN A WEEK'))
  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: 'chord',
  title: 'Chord diagram',
  category: 'flow',
  description: 'Handoffs between agents around a ring: ribbon width by handoffs each way, with the busiest pair in Claude orange and its count.',
  element: ui => ui.Svg({ source: (source ??= draw()), alt: `Chord diagram of handoffs between ${AGENTS.length} agents, with the ${AGENTS[PAIR[0]]} and ${AGENTS[PAIR[1]]} pair in Claude orange, sample data`, width: W, height: H }),
}

Imports d3-chord 3.0.1 (ISC), d3-shape 3.2.0 (ISC), bundled with its licence in look's hooks/vendor/.

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).