KQ-2095 · SWAP/SAVINGS

Swap Savings

This month's assistant spend by task and model with a what-if mode: as you move a share of a task's traffic to another model, the from-model's bar drops and the to-model's bar rises to their projected heights on springs.glide — chasing the slider so they arrive just behind your hand — over ghost outlines that hold today's heights, while the savings figure rolls on springs.snap beside a quality note that turns warn past your floor. Each share is a real slider whose thumb follows the finger 1:1 and lands on its step on snap with the release velocity; arrows step it, Page Up and Page Down move a quarter, Home and End jump, R resets every share and Flip reverses the pair. In a narrow container the chart turns horizontal.

KQ-2095 · SWAP/SAVINGS

October spend by model

Waylight ProWaylight Lite

What-if · 1
Projected$3,920$4,327
Saves a month$4089%

Quality on moved traffic 91 → 88 · within your floor

Support replies—

Pro
Waylight Pro, Support replies: $1,944 today, $1,944 projected
Lite
Waylight Lite, Support replies: $29 today, $29 projected
0%

Summaries−$408

Pro
Waylight Pro, Summaries: $1,176 today, $706 projected
Lite
Waylight Lite, Summaries: $34 today, $96 projected
40%

Extraction—

Pro
Waylight Pro, Extraction: $504 today, $504 projected
Lite
Waylight Lite, Extraction: $101 today, $101 projected
0%

Code review—

Pro
Waylight Pro, Code review: $540 today, $540 projected
Lite
Waylight Lite, Code review: $0 today, $0 projected
0%

Each share is a slider: arrows move it, Page Up and Page Down by a quarter, R resets every share.

save $408 · quality 91 → 88 · 1 change · applied none

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/swap-savings

Props

models
SwapModel[]
default defaultSwapModels
The models on the bill: { id, name, short?, inputPrice, outputPrice } per million tokens.
tasks
SwapTask[]
default defaultSwapTasks
What the traffic is for, in chart order: { id, label }.
usage
SwapUsage[]
default defaultSwapUsage
This month's tokens per task and model: { task, model, inputTokens, outputTokens }.
quality
Record<string, Record<string, number>>
default defaultSwapQuality
Quality per model and task, 0–100, from your evals.
fromModel
string
default the first model
The model traffic moves away from; Flip swaps the pair.
toModel
string
default the second model
The model traffic moves to.
mix / defaultMix
Record<string, number>
default — / {}
Share of each task's traffic moved, 0 to 1, controlled or initial.
onMixChange
(mix) => void
default —
Fires from the slider, key or Reset that changed a share, with the whole mix.
onApplyMix
(mix, projection) => void
default —
Apply mix was pressed.
onReset
() => void
default —
Reset (or R) put every share back to today's.
onCompare
(projection) => void
default —
Compare was pressed. Omit it and the button is not drawn.
status
"ready" | "loading" | "insufficient" | "error"
default "ready"
Usage is ready, loading, too thin to project from, or failed.
daysOfData
number
default 30
Days of traffic so far, for the not-enough-data state.
daysNeeded
number
default 14
Days a projection needs.
onRetry
() => void
default —
Try again was pressed after usage failed to load.
step
number
default 0.05
How far one arrow key moves a share.
qualityFloor
number
default 3
A drop in quality past this many points is flagged.
title
string
default "October spend by model"
The panel's heading.
formatMoney
(amount: number) => string
default "$1,240", by hand
How money is printed.
ghostStyle
"dashed" | "shade" | "cap"
default "dashed"
How today's heights are kept while the bars move: a dashed outline, a faint shade, or a cap line.
barWidth
number
default 32
Bar thickness in px; the gap between a group's bars widens for thin bars so their labels never collide.
accent
"cobalt" | "plum" | "mint" | "ink" | string
default "cobalt"
The to-model's bars, the sliders and the savings: a named pigment or any CSS colour.
disabled
boolean
default false
Read only: shares cannot move.
className
string
default —
Classes for the panel.