Capacity Stack

A stack of labelled buckets that fills a fixed-size track. Each bucket carries an explicit sizeGb and an optional tone; the track sizes to capacityGb (when given) or to the sum of the buckets otherwise. When the buckets exceed the capacity, the overflow is drawn as a trailing cb-error segment so the gap is read by length, not by inferred ratio. Vertical orientation stacks bottom-up like a memory tank filling; horizontal stacks left-to-right like a budget bar.

Capacity stack. Weights (fp16): 140 GiB; Gradients (fp16): 140 GiB; Optimizer (Adam fp32): 280 GiB; Activations: 80.0 GiB. Total: 640 GiB. Capacity: 80.0 GiB, over by 560 GiB.
Capacity stack640 GiB / 80.0 GiB
  • Weights (fp16)140 GiB
  • Gradients (fp16)140 GiB
  • Optimizer (Adam fp32)280 GiB
  • Activations80.0 GiB
  • over560 GiB
Customize
Buckets (GiB)
140 GiB
140 GiB
280 GiB
80 GiB
Device
80 GiB
vertical
Display

Installation

npx shadcn@latest add https://craftbits.dev/r/capacity-stack.json

Usage

import { CapacityStack } from "@craft-bits/core";
 
<CapacityStack
  buckets={[
    { id: "weights", label: "Weights", sizeGb: 140, tone: "accent" },
    { id: "grads", label: "Gradients", sizeGb: 140, tone: "warning" },
    { id: "optim", label: "Optimizer", sizeGb: 280, tone: "success" },
    { id: "acts", label: "Activations", sizeGb: 80 },
  ]}
  capacityGb={80}
/>

Switch to a horizontal budget bar:

<CapacityStack buckets={buckets} capacityGb={80} orientation="horizontal" />

Hide labels when you only want the bar:

<CapacityStack buckets={buckets} capacityGb={80} showLabels={false} />

Understanding the component

  1. One track, many segments. Each bucket is a child motion.span whose height (vertical) or width (horizontal) animates to its share of the track. The track itself is a single rounded box.
  2. capacityGb sizes the track. When provided, the segments are normalised against capacityGb, so the visible length of every bucket reflects its share of the budget, not of the sum. Drop capacityGb and the track sizes to the sum.
  3. Overflow segment. When sum(sizeGb) > capacityGb, the gap is drawn as a trailing cb-error segment with an outlined edge. The header total also flips to cb-error so the failure mode is unmissable.
  4. Free headroom. When the stack fits, the remaining track stays the muted background colour and the label list adds a free row with the gap in GiB. No free row appears when no capacityGb is given.
  5. Vertical reads bottom-up. Vertical orientation reverses the render order so the first bucket sits at the bottom (memory filling a tank). Horizontal preserves the original order (budget bar reading left-to-right).
  6. SPRINGS.smooth everywhere. Segment sizing animates with the canonical smooth spring, staggered by STAGGER between siblings. prefers-reduced-motion: reduce collapses every spring to an instant swap.

Props

PropTypeDefaultDescription
bucketsreadonly CapacityStackBucket[]requiredLabelled segments in render order.
capacityGbnumberTotal available capacity in GiB. Drives the track length and the overflow segment.
orientation`'vertical''horizontal'`'vertical'
showLabelsbooleantrueRender the labelled bucket list under the bar.
transitionTransitionSPRINGS.smoothSpring used for segment-size transitions.
classNamestringMerged onto the root via cn().

The CapacityStackBucket shape: { id: string; label: string; sizeGb: number; tone?: 'accent' | 'warning' | 'success' | 'error' }.

Accessibility

  • The figure is role="figure" with a hidden summary listing every bucket, the total, the capacity, and the overflow or headroom — screen readers hear the story whenever buckets change.
  • Segments are role="presentation" because the underlying figures already convey the meaning textually; the visual bar is decorative once the summary is in place.
  • Colour is never the only signal — every bucket has a label, a tone swatch, and a GiB readout; the header total flips to cb-error and the labels list adds an explicit over row when the stack overflows.
  • Motion respects prefers-reduced-motion: reduce.

Credits

  • Extracted from: craftingattention (app/src/lessons/primitives/nn/CapacityStack.tsx). The source was a parameter-count expressivity widget — a 2-param line growing into a 10-param wiggly curve to teach "more parameters = more capacity". The library extract reframes the name around its more common usage: visualising GPU memory capacity (weights, gradients, optimizer state, activations) as a labelled stack of buckets that may or may not fit the device. The pure plotting primitive: buckets in, normalised stack out, with vertical or horizontal orientation, motion-library springs, and an overflow segment when the stack exceeds capacityGb.