Files
PIG-Demo/src/components/demo/MetricChart.tsx
T
karti-ai a21596b3e4
ci / web (push) Successful in 2m42s
ci / python (push) Successful in 3m8s
Redesign in Prime Intellect's design language, both themes, three viewports
Eighteen agents: three design directions judged on whether a COO on a phone
actually learns what an environment is, on craft, and on landing without a
rewrite; one spec; a foundation of measured tokens; six build lanes; three
browser verifiers; a final gate pass.

The materials are Prime Intellect's, measured from their site: near-black
grounds, one green, sharp radii, mono small-caps labels, Geist and Geist Mono
self-hosted because production CSP is font-src 'self'. Two of their own greys
fail contrast on their own ground (#737373 is 4.02:1, #6E6E6E is 3.73:1 on
#0F0F0F), so --muted is lifted and the CSS comment carries the number — or
someone will 'correct' it back. Every text-on-ground pair in both themes is
tabulated in src/index.css with its measured ratio.

The two rules that resolved every conflict: data is mono, sentences are sans;
the language wins on materials, the lesson wins on legibility. Light mode is a
finished paper theme, not an inversion.

What did not change: the derived-tabs contract, the honesty markers, the
isolation lint, every gate. 419 contract checks, entry chunk at 74% of budget,
zero horizontal overflow on any route at 390/1024/1440 in either theme.

Also flips Alert Triage to status 'live' — the pipeline built it but never
promoted it, so it was badged SPEC on its own playable page and the home page
counted one environment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mt6sHQHEnEYrJZvoMCJSB
2026-08-28 21:41:15 -07:00

133 lines
4.3 KiB
TypeScript

import {
CartesianGrid,
Line,
LineChart,
ReferenceLine,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts';
import type { TooltipProps } from 'recharts';
import { formatNumber } from './format';
export interface MetricPoint {
/** Whatever the x axis is counting: checkpoint, step, arm name. */
x: string | number;
y: number;
}
export interface MetricChartProps {
data: MetricPoint[];
/** The rule the headline number is being compared against. */
baseline?: { value: number; label: string };
height: number;
/** Off under `prefers-reduced-motion`; recharts animates on mount by default. */
animate: boolean;
digits?: number;
}
/*
* Every colour is an `hsl(var(--…))` string read from the token layer at paint
* time, so the chart follows the theme toggle without a re-render and no hex
* ever lands in this file. The series takes `--tab-underline`, which is the
* one token that is the accent fill in dark and the accent INK in light — a
* 2px line on the page ground is a state indicator, and the raw accent is
* 1.47:1 against white.
*/
const SERIES = 'hsl(var(--tab-underline))';
const GRID = 'hsl(var(--border))';
const BASELINE = 'hsl(var(--border-strong))';
const TICK = 'hsl(var(--muted))';
/**
* The chart, in its own module so `React.lazy` can hold recharts out of the
* entry chunk. Nothing else in the shell may import this file directly — an
* ordinary import here defeats the whole arrangement and the entry chunk grows
* by ~100 kB without anyone noticing.
*/
export default function MetricChart({
data,
baseline,
height,
animate,
digits = 3,
}: MetricChartProps) {
return (
<div style={{ height }} className="w-full font-mono">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={data} margin={{ top: 8, right: 12, bottom: 4, left: 4 }}>
<CartesianGrid stroke={GRID} strokeDasharray="2 4" vertical={false} />
<XAxis
dataKey="x"
tick={{ fill: TICK, fontSize: 11, fontFamily: 'inherit' }}
tickLine={false}
axisLine={{ stroke: GRID }}
minTickGap={12}
/>
<YAxis
tick={{ fill: TICK, fontSize: 11, fontFamily: 'inherit' }}
tickLine={false}
axisLine={false}
width={40}
tickFormatter={(value: number) => formatNumber(value, digits > 2 ? 2 : digits)}
/>
{baseline ? (
<ReferenceLine
y={baseline.value}
stroke={BASELINE}
strokeDasharray="5 4"
// Right-anchored: a baseline near zero sits on the x axis, and
// a left-anchored label lands on the first tick's text.
label={{
value: baseline.label,
position: 'insideTopRight',
fill: TICK,
fontSize: 11,
fontFamily: 'inherit',
}}
/>
) : null}
<Tooltip
cursor={{ stroke: BASELINE }}
content={(props: TooltipProps<number, string>) => (
<ChartTooltip {...props} digits={digits} />
)}
/>
<Line
// `linear`, not `monotone`: a spline invents curvature between two
// measured points, and on a categorical axis (one point per
// recorded arm) that curve is a claim nobody measured.
type="linear"
dataKey="y"
stroke={SERIES}
strokeWidth={2}
dot={{ r: 3, fill: SERIES, strokeWidth: 0 }}
activeDot={{ r: 4.5, fill: SERIES, strokeWidth: 0 }}
isAnimationActive={animate}
animationDuration={400}
/>
</LineChart>
</ResponsiveContainer>
</div>
);
}
function ChartTooltip({
active,
payload,
label,
digits,
}: TooltipProps<number, string> & { digits: number }) {
if (!active || !payload || payload.length === 0) return null;
const value = payload[0]?.value;
return (
<div className="rounded-md border border-border bg-surface px-2.5 py-1.5 font-mono text-caption shadow-overlay">
<p className="text-muted">{String(label)}</p>
<p className="font-semibold text-fg">
{typeof value === 'number' ? formatNumber(value, digits) : '—'}
</p>
</div>
);
}