Cost Model Viz
Per-request cost distribution for an AI system. ~50 requests from the last hour are plotted on a log-scale Y-axis ($0.001 → $50); most cluster below $0.05, but a small handful of runaway agent loops with quadratic scratchpad growth blow past a configurable alert threshold and dominate the bill. Click any dot to drill into the full token-times-price breakdown — model, input / output / cached counts, line-by-line cost math, model-call count, and (for anomaly-tier requests) the scratchpad-growth note.
The insight: per-request cost alerting is not redundant with monthly bill caps. A single 15-call agent loop on a quadratically-growing scratchpad can spend more than 40 normal requests combined — and it'll do it in the next minute, not at end-of-month.
Each dot is one API request over the last hour. The Y-axis is cost on a log scale — from fractions of a cent to tens of dollars. Notice how most requests cluster below $0.05, but a few outliers above the dashed line dominate the total bill. Click any dot to see where the money went.
Installation
npx shadcn@latest add https://craftbits.dev/r/cost-model-viz.jsonUsage
import { CostModelViz } from "@craft-bits/viz/cost-model-viz";
<CostModelViz />Drive the selection from outside (controlled mode):
const [selectedId, setSelectedId] = useState<number | null>(null);
<CostModelViz
selectedRequestId={selectedId}
onSelectionChange={setSelectedId}
/>;Bring your own dataset and threshold:
<CostModelViz
requests={myRequests}
alertThreshold={0.5}
onPhaseChange={(phase) => {
if (phase === "insight") trackAnomalyInspected();
}}
/>Understanding the component
- The scatter plot. Each request becomes one
<motion.circle>. Dot radius scales with tier (normal: 3,elevated: 4,anomaly: 5.5) — the eye picks out the outliers before the color does. Selected dots inflate+2, hovered dots inflate+1, and unselected dots dim to0.2opacity while a selection is active. - Log-scale Y-axis. Cost compresses across four orders of magnitude (sub-cent to tens of dollars). The grid lines mark each decade; the dashed line at
alertThresholdseparates "normal cluster" from "fix this loop". - Detail panel. A
mode="wait"AnimatePresenceswaps the panel on every selection. Rows enter on a tightSTAGGERcadence (SPRINGS.snap), the cost-breakdown card usesSPRINGS.smooth, and the anomaly scratchpad-note appears only fortier: "anomaly"requests. - Phase derivation. Selection drives a derived
CostModelVizPhase—overviewwhen nothing's selected,inspectingfor normal/elevated,insightfor anomaly. The narration paragraph and the phase indicator dot both follow. - Tier breakdown bar. A 3-segment bar under the chart shows where the dollars went (often
anomalyis<10%of count but>50%of cost). The width animates in once on mount via the override-abletransitionprop. - Reduced motion. Under
prefers-reduced-motion: reduce, every entrance — stat row, dot pop-in, detail panel, tier bar, scratchpad note — collapses toduration: 0.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
requests | readonly CostModelVizRequest[] | curated 50-request dataset | Requests to plot. |
alertThreshold | number | 0.15 | Cost above which a request is flagged as an anomaly. |
selectedRequestId | number | null | — | Controlled selection id. Pair with onSelectionChange. |
defaultSelectedRequestId | number | null | null | Uncontrolled initial selection. |
onSelectionChange | (id) => void | — | Fires after the selection changes. |
onPhaseChange | (phase) => void | — | Fires on every overview → inspecting → insight transition. |
transition | Transition | SPRINGS.smooth | Override the entrance spring for stats / detail / tier bar. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The root is
role="figure"with anaria-labeldescribing the dataset; the inner<svg>repeatsrole="img"with a color-legend description. - Every dot is a
role="button"with anaria-labelcarrying the query preview, cost, and tier, and is reachable withTab+ activated withEnter/Space. - A polite live region announces the current selection (with cost + tier + model-call count) or, when nothing is selected, the dataset-level summary (total requests, total cost, anomaly count).
Escapeclears the selection and returns focus behaviour to the overview phase.- Color is never the only signal — dot radius scales with tier, the narration paragraph names the phase, the detail panel labels every value, and the tier-breakdown legend prints "normal / elevated / anomaly" alongside the swatches.
- Motion respects
prefers-reduced-motion: reduce— every entrance collapses to instant.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/systems/CostModelViz.tsx). The source was a lesson-scope viz that imported raw--color-ink-*/--color-accent-400/--color-surface-raisedtokens, depended on the project'sSPRINGS.gentle/SPRINGS.snappy/STAGGER.tightre-exports, and pinned tier colors to literaloklch(…)values. The viz extract remaps the palette tovar(--cb-success)/var(--cb-warning)/var(--cb-error)/var(--cb-fg-*)semantic tokens, re-keys the springs to the canonicalSPRINGS.snap/SPRINGS.smooth/SPRINGS.bouncyandSTAGGERconstant from@craft-bits/core/motion, hoists the 50-request dataset andalertThresholdto props (with the original curated dataset shipped asCOST_MODEL_VIZ_DEFAULT_REQUESTS), wraps the component inforwardRef, acceptsclassNameviacn(), spreads...propson the root, exposesselectedRequestIdvia the controlled / uncontrolled Radix pattern with anonSelectionChangeevent, and adds anonPhaseChangeevent so consumers can wire the viz to external scoreboards or tracking.