Token Budget Allocator
A direct-manipulation visualiser for how production AI systems allocate a fixed token budget across competing context sections using priority-based truncation. The learner drags a single budget slider and flips per-section priority chips — MUST, HIGH, MEDIUM, LOW — and a stacked SVG bar chart redistributes tokens in real time.
The deterministic allocator runs four passes: MUST first (full request), then HIGH, MEDIUM, LOW, with proportional fill within each tier when budget runs out. Sections that don't fit show a striped truncation overlay. When MUST overflows, the summary turns red and the narration calls out that the prompt builder would fail.
Phase-keyed narration moves through observe → adjusting → insight as the learner explores.
3,500 MUST20,000 HIGH8,500 MEDIUM0 LOW
5 sections want 50,000 tokens, but only 32,000 are available. The allocator fills MUST first, then HIGH, MEDIUM, LOW. Something has to give.
Installation
npx shadcn@latest add https://craftbits.dev/r/token-budget-allocator.jsonUsage
import { TokenBudgetAllocator } from "@craft-bits/viz/token-budget-allocator";
<TokenBudgetAllocator />Custom starting budget and slider bounds:
<TokenBudgetAllocator
defaultBudget={64_000}
minBudget={16_000}
maxBudget={200_000}
/>Subscribe to allocations from outside:
<TokenBudgetAllocator
onAllocate={(rows) => {
const truncated = rows.filter((r) => r.truncated).map((r) => r.name);
console.log("truncated", truncated);
}}
/>Understanding the component
- Coordinate system. The plot is a
560 × dynamicSVG with origin top-left. The left100pxholds section names; the rest is the budget bar track, with60pxon the right reserved for the per-row count label. The bar height grows with the section count. - Allocation algorithm. A pure function runs four passes: fill all
MUSTfirst, then walkHIGH→MEDIUM→LOW. Inside a tier, if there's enough budget, everyone gets their full request; otherwise the remaining budget is distributed proportional to each section's request and every section in that tier is marked truncated. - Budget-line scaling. The dashed accent line marks the budget edge. The bar's pixel scale is
BAR_W / max(totalRequested, budget), so dragging the budget past the total requested doesn't compress everything — it just shrinks the budget line's position relative to the rightmost bar end. - Truncation overlay. When
allocated < requested, a striped overlay (45° rotatedpattern) fills the missing portion. The pattern colour matches the section's priority. - Imperative animation. Both per-row bar widths and the dashed budget line are animated via motion's
animate()so the SVG never re-renders per frame. Underprefers-reduced-motion: reduce, every animation collapses to an instant attribute set. - Phase machine.
observeis the initial state,adjustingtriggers once the budget slider moves,insighttriggers once any priority chip is flipped. Phase drives the tint of the narration paragraph; aMUSToverflow short-circuits to the error tint.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
sections | readonly TokenBudgetAllocatorSection[] | five-section LLM prompt anatomy | Sections to allocate across. |
defaultBudget | number | 32_000 | Initial budget in tokens. |
minBudget | number | 8_000 | Minimum budget the slider can reach. |
maxBudget | number | 128_000 | Maximum budget the slider can reach. |
budgetStep | number | 1_000 | Slider step size in tokens. |
onBudgetChange | (budget) => void | — | Fires when the budget slider moves. |
onAllocate | (allocated) => void | — | Fires when allocation is recomputed. |
transition | Transition | SPRINGS.snap | Override the bar-width spring. |
budgetLineTransition | Transition | SPRINGS.smooth | Override the budget-line spring. |
className | string | — | Merged onto the root via cn(). |
Accessibility
- The viz SVG is
role="img"with anaria-labelsummarising budget, total requested, and truncated section count. - The budget slider is a native
<input type="range">with full keyboard support (arrow keys advance onebudgetStep). - Each priority chip is a
<button>witharia-pressedand a descriptivearia-label, plus a visiblefocus-visiblering. - A visually hidden
sr-onlystatus region witharia-live="polite"andaria-atomicannounces the budget, truncated count, and total on every change. - The narration paragraph below the SVG is
aria-live="polite"and announces phase transitions in prose. - Colour is never the only signal — the summary line names each priority tier in plain text and per-row labels read
allocated / requestednumerically. - Motion respects
prefers-reduced-motion: reduce— every animation collapses to an instant attribute set.
Credits
- Extracted from:
craftingattention(app/src/lessons/primitives/systems/TokenBudgetAllocator.tsx). The source was a lesson primitive wrapped in the project'sSvgLabeltext helper andChallengeBtnchrome, consumed lesson-track palette tokens (--color-fail-400,--color-warn-400,--color-accent-400,--color-ink-*), and used the project'sca-narrationparagraph. The viz extract drops the lesson chrome, swaps the palette tovar(--cb-*)semantic tokens, replacesSvgLabelwith bare<text>carrying the canonicalcb-*font, exposessections/defaultBudget/minBudget/maxBudget/budgetStep/onBudgetChange/onAllocate, and pins the imperative bar-width animation toSPRINGS.snapand the dashed-line animation toSPRINGS.smoothwith overrides.