Level Work Bars

A row-per-level visualization of the work done at every depth of a divide-and-conquer recursion tree. Each level draws count bars whose individual widths encode workPerNode, so the row totals reveal whether the per-level work grows, shrinks, or stays constant — the geometric structure that makes the Master Theorem (and the O(n log n) total work of merge sort) visible rather than algebraic.

Customize
Highlight
none
Annotations

Installation

npx shadcn@latest add https://craftbits.dev/r/level-work-bars.json

Usage

import { LevelWorkBars } from "@craft-bits/core";
 
const levels = [
  { count: 1, workPerNode: 8, label: "T(n)" },
  { count: 2, workPerNode: 4, label: "T(n/2)" },
  { count: 4, workPerNode: 2, label: "T(n/4)" },
  { count: 8, workPerNode: 1, label: "T(1)" },
];
 
<LevelWorkBars levels={levels} />

Highlight one specific level to draw the eye to a recurrence step:

<LevelWorkBars levels={levels} highlightLevel={1} />

Understanding the component

  1. One row per recursion level. Index 0 is the root; deeper indices are deeper subproblems. Each row draws count bars whose widths are proportional to workPerNode, so a row's total bar width tracks the work performed at that level.
  2. Widths normalised to the largest workPerNode. The merge-sort root does n work in a single bar; the leaves do 1 work each, in n bars. The widths reflect per-node cost — not per-level total — so the depth/fan-out/cost relationship is preserved.
  3. layoutId per bar. When the caller animates between two recurrences (e.g. T(n) = 2T(n/2) + n vs T(n) = 4T(n/2) + n), bars glide via SPRINGS.smooth instead of cross-fading.
  4. Highlighted level scales 1.03 + accent fill. Pass highlightLevel={k} to single out a row; the others drop to the muted scale.
  5. Optional running totals. showTotals adds a count × work = total chip on the right of each row; showSum adds a sigma row underneath summing the work across every level.
  6. Reduced motion. Layout transitions and bar entrances collapse to { duration: 0 } so the final state is reachable without animation.

Props

PropTypeDefaultDescription
levelsreadonly { count: number; workPerNode: number; label?: string }[]requiredOne entry per recursion level. Returns null when empty.
highlightLevelnumber-1Index of the level to render in the accent color. -1 shows every level equally.
showTotalsbooleantrueRender the count × work = total chip on the right of each row.
showSumbooleantrueRender a sigma-total row below the level rows.
classNamestringMerged onto the outer <div> via cn().

Accessibility

  • The root is role="img" with an aria-label that flattens every level into a readable trail and reports the grand total.
  • Color is never the only signal — highlighted and muted rows are distinguishable by scale, opacity, and the per-row total.
  • Bars carry aria-hidden="true"; the row's textual content carries the screen-reader meaning.
  • Motion respects prefers-reduced-motion: layout transitions and bar entrances collapse to { duration: 0 }.

Credits

  • Extracted from: algoflashcards (src/lessons/primitives/viz/LevelWorkBars.tsx). The original was a one-bar-per-level chart driven by a single workPerLevel: number[] plus a precomputed maxWork, used to land the "every level is n comparisons" insight for merge sort. The library version reframes the structure around the recurrence itself — every level is count × workPerNode — supports a highlightLevel accent, an optional sigma-total row, and shared layoutId-driven transitions between recurrences.