KQ-2096 · UNIT/COST

Unit Cost

An AI usage panel that divides the period's spend by the outcomes it produced and draws it as a real fraction: when the period or outcome changes, the numerator and denominator roll independently on springs.snap, each changed digit's strip travelling to its new face with the denominator a beat behind, while a number that gains a place grows a column on springs.glide and the quotient fades in once both have landed. Beside it a trend of cost per outcome over twelve weeks, its target band shaded, works as the period picker: the cursor follows the finger 1:1, picks each week it passes and settles on snap with the release velocity, a change of outcome morphs the whole line on glide, and the target line's handle drags to a new target that commits to the cent on snap. Outcomes are a radiogroup with arrow keys, the trend and the target are sliders, and the trend also reads as a table.

KQ-2096 · UNIT/COST

Gaugeworks · support assistant

AI spend per finished outcome

Week of Oct 12: $902 over 2,416 tickets resolved, $0.37 a ticket, in the target band.

$0.40

tickets resolved · Oct 12 · $0.37 each · in band

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/unit-cost

Props

outcomes
UnitCostOutcome[]
default defaultUnitCostOutcomes
What spend is divided by: { id, label, short?, unit, target, tolerance? }. The target is the cost per outcome the team aims for; tolerance is half the band's width as a share of it.
usages
UnitCostUsage[]
default defaultUnitCostUsages
The usage lines spend is reported under: { id, name }. Unmapped lines are named in the unmapped note.
periods
UnitCostPeriod[]
default defaultUnitCostPeriods
The periods, oldest first: { id, label, spend (dollars per usage id), outcomes (count per outcome id), partial? }. A partial last period is drawn dashed.
mapping
Record<string, string | null>
default defaultUnitCostMapping
Which outcome each usage line produces. Usage mapped to nothing is summed as unmapped spend; an outcome with no usage mapped shows a dash and says so.
outcome / defaultOutcome
string
default the first outcome
The outcome spend is divided by, controlled or initial.
onOutcomeChange
(id: string, outcome: UnitCostOutcome) => void
default —
Fires from the radio or arrow key that changed the outcome.
period / defaultPeriod
string
default the last period
The period the fraction reads, controlled or initial.
onPeriodChange
(id: string, period: UnitCostPeriod) => void
default —
Fires as the trend's cursor, a table row or an arrow key picks a period.
targets
Record<string, number>
default —
Controlled targets per outcome id, overriding each outcome's own.
onSetTarget
(outcomeId: string, value: number) => void
default —
Fires when the target handle is dragged or stepped to a new value.
onMapUsage
(usageIds: string[]) => void
default —
“Map usage” was pressed on the unmapped-spend note, with the usage ids that feed no outcome. Omit it and the note is plain text.
minOutcomes
number
default 40
Below this many outcomes a period's cost is called too few to trust and drawn as a hollow dot.
defaultView
"chart" | "table"
default "chart"
The trend as a chart or a table at first; the Chart and Table buttons switch it.
status
"ready" | "loading" | "error"
default "ready"
Usage arrived, is on its way (a still skeleton), or failed (a message and Try again).
onRetry
() => void
default —
“Try again” was pressed after usage failed to load.
title
string
default "Gaugeworks · support assistant"
The panel's heading.
subtitle
string
default "AI spend per finished outcome"
Under the heading.
formatMoney
(amount: number, kind: "total" | "each") => string
default hand formatter
How money prints: whole totals (“$1,284”) and per-outcome costs (“$0.37”, three places under twenty cents).
fractionStyle
"stacked" | "slashed" | "ratio"
default "stacked"
The fraction's form: one figure over a rule over the other, a slashed nut fraction, or one line with a division sign.
bandStyle
"shade" | "hatch" | "rules"
default "shade"
How the target band is drawn: a soft wash, diagonal hatching with edges, or only its two dashed edges.
accent
"cobalt" | "plum" | "mint" | "ink" | string
default "cobalt"
The line, band and selection colour; any CSS colour works.
disabled
boolean
default false
Read only: nothing can be picked, dragged or set.
className
string
default —
Classes for the panel, e.g. a max height; it scrolls inside its own box.