ModsCode / Gallery / Designs / Step line by release
Step line by release
Daily error rate as a step line with each release marked under the plot and labelled with its mean; the worst release is red.


hooks/designs/step-line.mjs
// step-line: 48 days of tool-call error rate across six releases, in candle's look. A step line, not a
// slope, because the rate holds until the next deploy changes it: each day sits on its release's level
// with a seeded wobble of up to 12%. Releases ship on days 2, 10, 17, 25, 33 and 41 (at least 7 days,
// about 48px, apart, so the 9px names under their stubs never touch). Each release is labelled with the
// mean of its own days: v1.4 0.8%, v1.5 0.6%, v1.6 0.7%, v1.7 2.3%, v1.8 0.9%, v1.9 0.5%. v1.7 has the
// highest mean, so it is the worst release: its stub, name, mean and step (risers included) turn DOWN
// over a 25% DOWN area, the same tint area-threshold uses for a breach. The hero is today's rate
// (0.47%). Means are computed from the days, never typed. Step path: d3-shape 3.2.0 curveStepAfter
// (ISC). Sample data only.
import { line, curveStepAfter } from '../vendor/d3.mjs'
const W = 380
const H = 180
const STAGE = '#FAF9F5'
const INK = '#141413'
const MUTED = '#73726C'
const DOWN = '#AB2B3F'
const FONT = "'Inter Tight','Segoe UI',system-ui,sans-serif"
const PLOT = { left: 36, right: 368, top: 44, bottom: 140 }
const N = 48 // days
const f = n => n.toFixed(1)
// Estimated text width: m, w and % run wide, spaces and dots narrow, the rest about 0.56 em
const wide = (s, size) => [...s].reduce((w, c) => w + size * (/[mwMW%]/.test(c) ? 0.85 : /[ .,:il1]/.test(c) ? 0.3 : 0.56), 0)
// A seeded walk, so the picture is the same on every render
function rng(seed) {
return () => (seed = (Math.imul(seed, 1103515245) + 12345) & 0x7fffffff) / 0x7fffffff
}
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>`
// The day each release shipped and the error rate (%) it settles at; days 0-1 still run v1.3
const BEFORE = 0.9
const RELEASES = [
{ name: 'v1.4', day: 2, level: 0.8 },
{ name: 'v1.5', day: 10, level: 0.6 },
{ name: 'v1.6', day: 17, level: 0.7 },
{ name: 'v1.7', day: 25, level: 2.3 },
{ name: 'v1.8', day: 33, level: 0.9 },
{ name: 'v1.9', day: 41, level: 0.5 },
]
// Each day sits on its release's level with a seeded wobble of up to +-12% of it
function sample() {
const rnd = rng(20261019)
const out = []
for (let d = 0; d < N; d++) {
const rel = RELEASES.filter(r => r.day <= d).pop()
const level = rel ? rel.level : BEFORE
out.push(Math.round(level * (0.88 + rnd() * 0.24) * 100) / 100)
}
return out
}
function draw() {
const vals = sample()
const top = Math.ceil(Math.max(...vals) * 1.15)
const x = d => PLOT.left + ((PLOT.right - PLOT.left) * d) / N // day d spans x(d) to x(d + 1)
const y = v => PLOT.bottom - ((PLOT.bottom - PLOT.top) * v) / top
// The mean of each release's days, and the worst release by that mean
const spans = RELEASES.map((r, k) => {
const end = k + 1 < RELEASES.length ? RELEASES[k + 1].day : N
const days = vals.slice(r.day, end)
return { ...r, end, mean: days.reduce((a, b) => a + b, 0) / days.length, high: Math.max(...days) }
})
const worst = spans.reduce((a, b) => (b.mean > a.mean ? b : a))
const parts = [`<rect width="${W}" height="${H}" rx="4" fill="${STAGE}"/>`]
// Header: today's rate on the release that is live now
const now = vals[N - 1]
const live = spans[spans.length - 1]
const hero = `${now.toFixed(2)}%`
parts.push(text(12, 24, hero, { size: 14, fill: INK }))
parts.push(text(12 + wide(hero, 14) + 8, 24, `TOOL-CALL ERRORS TODAY ON ${live.name}`))
// Left scale: 4px stubs, no axis line
for (let v = 0; v <= top; v++) {
parts.push(`<line x1="${PLOT.left - 4}" x2="${PLOT.left}" y1="${f(y(v))}" y2="${f(y(v))}" stroke="${MUTED}" stroke-width="1"/>`)
parts.push(text(PLOT.left - 8, y(v) + 3, `${v}%`, { anchor: 'end' }))
}
// Each release: a hairline up the plot where it shipped, a stub and its name under the plot
for (const s of spans) {
const bad = s === worst
const rx = x(s.day)
parts.push(`<line x1="${f(rx)}" x2="${f(rx)}" y1="${PLOT.top}" y2="${PLOT.bottom}" stroke="${INK}" stroke-opacity="0.08"/>`)
parts.push(`<line x1="${f(rx)}" x2="${f(rx)}" y1="${PLOT.bottom + 2}" y2="${PLOT.bottom + 6}" stroke="${bad ? DOWN : MUTED}" stroke-width="1"/>`)
parts.push(text(rx, PLOT.bottom + 17, s.name, { fill: bad ? DOWN : MUTED, anchor: 'middle' }))
}
// The step line: one more point at the right edge so the last day keeps its width
const pts = [...vals.map((v, d) => [x(d), y(v)]), [x(N), y(vals[N - 1])]]
const step = line().curve(curveStepAfter).digits(1)
const path = step(pts)
parts.push(`<path d="${path}L${f(x(N))},${PLOT.bottom}L${f(x(0))},${PLOT.bottom}Z" fill="${INK}" fill-opacity="0.08"/>`)
parts.push(`<path d="${path}" fill="none" stroke="${INK}" stroke-opacity="0.85" stroke-width="1"/>`)
// The worst release's days again, risers included, in DOWN over a 25% DOWN area
const bad = [[x(worst.day), y(vals[Math.max(0, worst.day - 1)])], ...vals.slice(worst.day, worst.end).map((v, i) => [x(worst.day + i), y(v)]), [x(worst.end), y(vals[worst.end - 1])]]
if (worst.end < N) bad.push([x(worst.end), y(vals[worst.end])])
const badPath = step(bad)
parts.push(`<path d="${badPath}L${f(x(worst.end))},${PLOT.bottom}L${f(x(worst.day))},${PLOT.bottom}Z" fill="${DOWN}" fill-opacity="0.25"/>`)
parts.push(`<path d="${badPath}" fill="none" stroke="${DOWN}" stroke-width="1"/>`)
// Each release's mean, centred over its days just above its highest day
for (const s of spans) {
const isWorst = s === worst
const cx = (x(s.day) + x(s.end)) / 2
parts.push(text(cx, y(s.high) - 5, `${s.mean.toFixed(1)}%`, { size: isWorst ? 10 : 9, fill: isWorst ? DOWN : MUTED, anchor: 'middle' }))
}
parts.push(text(12, H - 6, `SAMPLE ERROR RATE, ${N} DAYS`))
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: 'step-line',
title: 'Step line by release',
category: 'time',
description: 'Daily error rate as a step line with each release marked under the plot and labelled with its mean; the worst release is red.',
element: ui => ui.Svg({ source: (source ??= draw()), alt: 'Step line of daily tool-call error rate across releases, the worst release shaded red, sample data', width: W, height: H }),
}
Imports 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).