WindowBudget
A sliding-window viewer fused with a budget meter. The caller supplies an array of numbers, an inclusive window interval start, end, a budget cap (total ops allowed), and the current ops consumed so far. The component renders the array as a row of cells with the active window highlighted, and a token-stack meter underneath that drains as current grows. As the remaining budget crosses 30 percent the meter flips to warning styling; below 15 percent it pulses critical.
Pure visualization primitive — no protocol logic, no narration, no scoring. Drop into any sliding-window narrative (brute force versus incremental, fixed versus variable window, monotonic deque) and layer narration, predictions, or audio around it. The callers reducer drives window and current; the component owns the layout, the meter, and the motion.
Installation
npx shadcn@latest add https://craftbits.dev/r/window-budget.jsonUsage
import { WindowBudget } from "@craft-bits/core";
<WindowBudget
array={[2, 7, 1, 8, 2, 8, 1, 4, 5, 9]}
window={{ start: 0, end: 3 }}
budget={40}
current={4}
/>Cells hidden, meter only — just the draining token stack for a header chip:
<WindowBudget
array={values}
window={{ start: 0, end: 3 }}
budget={40}
current={10}
hideCells
/>Custom meter caption — replace the default chip with a caller-formatted node:
<WindowBudget
array={values}
window={{ start: 0, end: 3 }}
budget={40}
current={10}
formatMeter={({ remaining, total }) => "ops left: " + remaining + " / " + total}
/>Understanding the component
- Inclusive window.
window={ start, end }is closed on both ends —start === endis a single-cell window. Out-of-range values clamp to the array bounds. - Budget clamps for display.
currentis clamped to the range zero throughbudgetbefore render. Pass a value abovebudgetand the meter shows zero remaining — it never overflows. - Token-stack meter. Each token represents one op when
budget <= 24. Above that, ops group into chunks ofceil(budget / 24)so the row never exceeds 24 dots; the chunk size is announced in the caption. - Three urgency tiers. Above 30 percent remaining the meter sits in the accent tone. Below 30 percent it shifts to warning. Below 15 percent it pulses with a 0.5s critical loop.
- Exhausted state. When
current >= budgetthe meter renders zero alive tokens and adds an inline "exhausted" tag in the error tone. - Reduced motion. When
prefers-reduced-motion: reduceis set the cell scale, the meter pulses, and the dot stagger all collapse to instant.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
array | readonly number[] | required | Source array. Caller owns the values. |
window | { start: number; end: number } | required | Active inclusive window interval. Clamped to the array bounds. |
budget | number | required | Total operations the search is allowed to consume. |
current | number | required | Operations consumed so far. Clamped to [0, budget]. |
tone | "default" | "accent" | "success" | "warning" | "error" | "accent" | Semantic tone for the window highlight and meter accent. |
title | ReactNode | — | Optional title rendered above the cells. |
hideCells | boolean | false | Hide the array cell row. |
hideMeter | boolean | false | Hide the token-stack budget meter. |
formatMeter | (state) => ReactNode | — | Override the meter caption with a caller-formatted node. |
className | string | — | Merged onto the outer <div> via cn(). |
Accessibility
- The root carries
role="group"witharia-roledescription="window budget"and anaria-labelsummarising the active window and remaining budget on every render. - An off-screen
aria-live="polite"summary mirrors the visible state so screen-reader users hear the window and meter advance. - Each cell has an
aria-labelnaming its index, value, and whether it sits inside the active window. - The meter is
role="meter"witharia-valuenow,aria-valuemin, andaria-valuemaxmatching the remaining budget — assistive tech reports it as a real progress signal. - Urgency is conveyed by colour, scale pulse, and an explicit "exhausted" tag — never colour alone.
- Motion respects
prefers-reduced-motion: reduce— cell scale, meter pulse, and dot stagger collapse to instant.
Credits
- Extracted from:
algoflashcards(src/lessons/primitives/observation/WindowBudget.tsx). The source was a 2300+ line four-phase sliding-window lesson bundling a brute-force tap-to-count Phase 1 with a hard budget cap, a Discovery moment where the student taps the overlap between two windows, a Phase 2 incremental update with directional and consequence prediction gates, a Phase 3 code bridge driven byMagicMoveBlockthat morphs the nested loop into a compact single-loop slide, aPhaseSummary4-beat cinematic with arrow-and-savings-badge reveal, audio cues, scoring, per-distractorPredictionGatefeedback, mood-driven container palettes, and Done-screen sparkle motion. The library extract strips every lesson concern and keeps only the playback primitive: the highlighted window row, the token-stack budget meter with its three urgency tiers, and the caller-controlledwindowandcurrentprops.