Inverted Scaling Viz
A scaling-law canvas with room for inverse scaling laws. One or more curves of metric vs model size are drawn on a shared log-x chart so the usual upward curve (standard scaling) and a downward curve (inverse scaling — the surprising case where bigger models do worse) sit side by side.
The classic teaching pair is a textbook capability that improves smoothly with parameter count, alongside a task like TruthfulQA where larger models confidently reproduce common misconceptions more often.
Installation
npx shadcn@latest add https://craftbits.dev/r/inverted-scaling-viz.jsonUsage
import { InvertedScalingViz } from "@craft-bits/core";
<InvertedScalingViz
curves={[
{
id: "standard",
label: "Standard task",
tone: "accent",
points: [
{ size: 1e7, metric: 0.18 },
{ size: 1e9, metric: 0.52 },
{ size: 1e12, metric: 0.85 },
],
},
{
id: "inverse",
label: "Inverse-scaling task",
tone: "warning",
points: [
{ size: 1e7, metric: 0.62 },
{ size: 1e9, metric: 0.46 },
{ size: 1e12, metric: 0.17 },
],
},
]}
/>Pin the highlight declaratively and lose the legend interaction:
<InvertedScalingViz curves={curves} highlightId="inverse" />Drive the highlight from outside:
<InvertedScalingViz
curves={curves}
currentCurveId={selected}
onCurrentCurveChange={setSelected}
/>Swap to a linear x-axis when the sizes are small and the log isn't pulling its weight:
<InvertedScalingViz curves={curves} xScale="linear" />Anatomy
- Multi-line chart, log-x by default. Scaling-law plots conventionally use a log x-axis so powers-of-ten parameter counts space out evenly. The y-axis stays linear — accuracy, loss, and calibration error all read better unwarped.
- Tone signals the regime. Each curve carries a tone (
accent/warning/success). The canonical teaching pairing is standard scaling incb-accentand inverse scaling incb-warning;successis held in reserve for the "fixed" curve in a before-and-after comparison. - One highlight, the rest dim.
highlightId(or the internal legend chip) emphasises one curve with a thicker stroke and larger dots and softens the others to ~45%. The chip strip is arole="radiogroup"; clicking toggles the highlight. - Auto-fit domain. The visible range is the bounding box of every point across every curve, padded multiplicatively under log and additively under linear so the first and last dots sit comfortably inside the plot.
- Trend glyph in the legend. Each chip ends in
↗,↘, or→based on the first-to-last delta of its curve — a colour-blind-safe shape signal for which curves are scaling and which are inverse-scaling. - Reduced motion.
prefers-reduced-motion: reducecollapses every spring to an instant swap; the chart still highlights, fades, and refits.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
curves | readonly InvertedScalingVizCurve[] | required | Curves to plot. Empty curves are skipped. |
xLabel | string | "Model size (params)" | X-axis title. |
yLabel | string | "Accuracy" | Y-axis title. |
xScale | 'linear' | 'log' | 'log' | X-axis scale — y is always linear. |
highlightId | string | — | One curve to emphasise. Wins over currentCurveId. |
currentCurveId | string | null | — | Controlled legend selection. Pair with onCurrentCurveChange. |
defaultCurrentCurveId | string | — | Uncontrolled initial selection. |
onCurrentCurveChange | (id: string | null) => void | — | Fires when a legend chip toggles the highlight. |
transition | Transition | SPRINGS.smooth | Spring for curve and dot transitions. |
className | string | — | Merged onto the root via cn(). |
The InvertedScalingVizCurve shape: { id: string; label: string; points: { size: number; metric: number }[]; tone?: 'accent' | 'warning' | 'success' }.
Accessibility
- The figure is
role="figure"with a hidden summary describing each curve's trend and endpoints — screen readers hear the story whenever the data changes. - Each dot carries an SVG
<title>exposing curve label, metric, and size in the native tooltip. - The legend is a
role="radiogroup"ofrole="radio"buttons — Tab walks the chips, Space and Enter toggle the highlight, and:focus-visiblepaints the accent ring. - Curves are differentiated by tone and by their trend glyph (
↗ / ↘ / →) in the legend — the inverse-scaling story survives without colour. - Motion respects
prefers-reduced-motion: reduce.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/nn/InvertedScalingViz.tsx). The source was a single-purpose dropout teaching widget — a clickable neuron row, a scaling toggle, inlineanimate()calls on circle and glow refs, a four-phase narration state machine,ChallengeBtnchrome, and raw--color-accent-*/--color-fail-*/--color-ink-*vars. Repurposed as the canvas the concept needs: a multi-curve metric-vs-size plot built onmotion.pathplusSPRINGS.smooth, semanticcb-*tokens, controlled and uncontrolled legend selection, and a colour-blind-safe trend glyph in every legend chip.