Adapter Budget Viz

Compare trainable-parameter budgets across PEFT methods on one shared base-model scale. One row per method, one horizontal track: each bar's width is the method's trainableParams divided by totalParams. Full fine-tune fills the whole track; LoRA, prefix tuning, and IA³ collapse to slivers — the cost gap reads as a single picture.

Adapter parameter-budget comparison.Adapter parameter budget. Base model: 7.0B parameters. Full FT: 7.0B (100%); LoRA r=8: 8.4M (0.120%); Prefix k=64: 1.3M (0.019%); IA³: 196.6K (<0.01%).
Trainable parametersbase = 7.0B
Customize
Base
7.0B
PEFT knobs
8
64
Detail

Installation

npx shadcn@latest add https://craftbits.dev/r/adapter-budget-viz.json

Usage

import { AdapterBudgetViz } from "@craft-bits/core";
 
<AdapterBudgetViz
  totalParams={7_000_000_000}
  methods={[
    { id: "full-ft", label: "Full FT",       trainableParams: 7_000_000_000, tone: "warning" },
    { id: "lora",    label: "LoRA r=8",      trainableParams: 8_388_608,    tone: "success" },
    { id: "prefix",  label: "Prefix tuning", trainableParams: 1_310_720 },
    { id: "ia3",     label: "IA³",           trainableParams: 196_608,      tone: "success" },
  ]}
/>

Drive the highlighted row from outside the component:

const [method, setMethod] = useState("lora");
 
<AdapterBudgetViz
  totalParams={7_000_000_000}
  methods={methods}
  currentMethod={method}
  onCurrentMethodChange={setMethod}
/>

Drop the per-row percentage readout for a denser figure:

<AdapterBudgetViz
  totalParams={7_000_000_000}
  methods={methods}
  showPercentages={false}
/>

Understanding the component

  1. One track, one denominator. Every row shares the same 0 → totalParams track. A bar that fills half the track represents a method that trains half of the base model's parameters. Bars clamp at 100% — anything past the base size pegs the track without overflowing the layout.
  2. Tones carry meaning. warning (Full FT) flags the cost reference; accent is the neutral PEFT default; success highlights methods worth recommending. Tones map to --cb-warning / --cb-accent / --cb-success, so re-theming the library re-themes the chart.
  3. Two readouts per row. A fmtCount parameter count (16.8M, 196K, 7.0B) on top, the same number as a percentage of base (0.24%, <0.01%, 100%) below. Both render in font-variant-numeric: tabular-nums so the right column stays aligned as the values move.
  4. Click-to-highlight. Every row is a native <button aria-pressed> — clicking (or hitting Enter / Space) selects that method. The selected row gets a muted background and its label + percentage adopt the tone colour. Controlled via currentMethod + onCurrentMethodChange, uncontrolled via defaultCurrentMethod.
  5. Spring on width. Bars animate with SPRINGS.smooth whenever methods or totalParams change. prefers-reduced-motion: reduce collapses the spring to duration: 0 so the bars snap instead.

Props

PropTypeDefaultDescription
methodsAdapterMethod[]Rows, top-to-bottom. Each has id, label, trainableParams, optional tone.
totalParamsnumberBase-model size. The denominator for every bar's width and percentage.
showPercentagesbooleantrueRender the per-row percentage under the parameter count.
currentMethodstringControlled selected id. Pair with onCurrentMethodChange.
defaultCurrentMethodstringfirst method's idUncontrolled initial selection.
onCurrentMethodChange(id) => voidFires when the user clicks or activates a row.
transitionTransitionSPRINGS.smoothSpring for bar-width animation.
classNamestringMerged onto the root via cn().

Accessibility

  • The root is role="figure" with a visually-hidden aria-live="polite" summary that re-announces the full comparison whenever methods or selection change.
  • Each row is a native <button> with aria-pressed and a descriptive aria-label that spells out the method, raw parameter count, and percentage — colour and tone are never the only signal.
  • Bars carry aria-hidden="true" so the underlying button label is the single source of truth for screen readers.
  • :focus-visible rings are drawn in --cb-accent over the page background so keyboard focus is unambiguous.
  • prefers-reduced-motion: reduce collapses width springs to duration: 0.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/nn/AdapterBudgetViz.tsx). The source was a lesson-mode storage-cost widget — a two-bar comparison of full-FT storage vs LoRA storage with sliders for task count and model size, a phase system (observescalinginsight), narration strings, and a breathing pulse. The library extract generalises the idea: any number of PEFT methods, one shared parameter-budget scale, controlled+uncontrolled selection. The phase / narration scaffolding lives in the consuming lesson, not the primitive.