KQ-2097 · CACHE/DIVIDEND
Cache Dividend
A month of a prompt cache drawn as one split bar per day, the cached and uncached parts of the day's input at one token scale, under a savings counter that reads what the cache saved through the day you are on. The bars are one slider: scrubbing across them lifts the day under the finger on springs.snap while its two parts open a hairline apart, dims the days after it on a short tween, and ticks the counter to the new total on snap for every day passed, as rolling digit columns, a counting figure or a figure over a gauge. The day's prompts are listed beside the bars as hit and missed, with why each miss missed, cross-fading between days with rows in cascade order; Left and Right move a day, Page Up and Page Down a week, and in a narrow container the bars become a week-by-week strip.
Oct 17 · $1,308.39 saved · 74% cached
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/cache-dividend
Props
- days
- CacheDay[]
- default defaultCacheDays
- The month's days with data, from day 1: { date, input, cached, writes?, prompts?: { id, name, tokens, hit, reason? }[] }.
- monthDays
- number
- default 31
- Days in the month; days without data are drawn as days to come.
- prices
- CachePrices
- default { input: 3, cached: 0.3, write: 3.75 }
- Dollars per million input tokens, uncached, read from cache and written to cache. Savings are cached × (input − cached) − writes × (write − input).
- day / defaultDay
- number
- default the last day with data
- The day the counter reads through, as an index into days; controlled or initial.
- onScrub
- (index: number, day: CacheDay) => void
- default —
- Fires as the scrub, a tap or an arrow key lands on a day (in the strip, the last day of the week).
- onOpenPrompt
- (prompt: CachePrompt, day: CacheDay) => void
- default —
- A prompt in the list was pressed. Omit it and the rows are plain.
- onExport
- (days: CacheDay[]) => void
- default —
- Export was pressed. Omit it and the button is not drawn.
- cache
- "on" | "off" | "warming"
- default "on"
- The cache is on, off (nothing cached; the counter reads $0 and an estimate is shown), or warming up (the first days hatched with a note).
- warmupDays
- number
- default 3
- While warming, how many of the first days are drawn as warm-up.
- estimateHitRate
- number
- default 0.8
- The hit rate the off-state estimate assumes, 0 to 1.
- status
- "ready" | "loading" | "error"
- default "ready"
- Usage arrived, is on its way (still ghost bars), or failed (a message and Try again).
- onRetry
- () => void
- default —
- “Try again” was pressed after usage failed to load.
- title
- string
- default "Coldbrook · support assistant"
- The panel's heading.
- subtitle
- string
- default "Prompt cache · October"
- Under the heading.
- formatMoney
- (amount: number) => string
- default "$1,284.60" by hand
- How money prints.
- splitStyle
- "stacked" | "mirror" | "share"
- default "stacked"
- Each bar's form: cached under uncached on one baseline, cached up and uncached down from a centre line, or every bar full height split by hit rate.
- counterStyle
- "odometer" | "count" | "gauge"
- default "odometer"
- The savings figure: rolling digit columns, a figure that counts through its values, or a figure over a gauge of the most the month could have saved.
- accent
- "cobalt" | "plum" | "mint" | "ink" | string
- default "cobalt"
- The cached colour, the gauge and the selection; any CSS colour works.
- disabled
- boolean
- default false
- Read only: the day cannot be scrubbed.
- className
- string
- default —
- Classes for the panel, e.g. a max height; it scrolls inside its own box.
| Prop | Type | Default | Description |
|---|---|---|---|
| days | CacheDay[] | defaultCacheDays | The month's days with data, from day 1: { date, input, cached, writes?, prompts?: { id, name, tokens, hit, reason? }[] }. |
| monthDays | number | 31 | Days in the month; days without data are drawn as days to come. |
| prices | CachePrices | { input: 3, cached: 0.3, write: 3.75 } | Dollars per million input tokens, uncached, read from cache and written to cache. Savings are cached × (input − cached) − writes × (write − input). |
| day / defaultDay | number | the last day with data | The day the counter reads through, as an index into days; controlled or initial. |
| onScrub | (index: number, day: CacheDay) => void | — | Fires as the scrub, a tap or an arrow key lands on a day (in the strip, the last day of the week). |
| onOpenPrompt | (prompt: CachePrompt, day: CacheDay) => void | — | A prompt in the list was pressed. Omit it and the rows are plain. |
| onExport | (days: CacheDay[]) => void | — | Export was pressed. Omit it and the button is not drawn. |
| cache | "on" | "off" | "warming" | "on" | The cache is on, off (nothing cached; the counter reads $0 and an estimate is shown), or warming up (the first days hatched with a note). |
| warmupDays | number | 3 | While warming, how many of the first days are drawn as warm-up. |
| estimateHitRate | number | 0.8 | The hit rate the off-state estimate assumes, 0 to 1. |
| status | "ready" | "loading" | "error" | "ready" | Usage arrived, is on its way (still ghost bars), or failed (a message and Try again). |
| onRetry | () => void | — | “Try again” was pressed after usage failed to load. |
| title | string | "Coldbrook · support assistant" | The panel's heading. |
| subtitle | string | "Prompt cache · October" | Under the heading. |
| formatMoney | (amount: number) => string | "$1,284.60" by hand | How money prints. |
| splitStyle | "stacked" | "mirror" | "share" | "stacked" | Each bar's form: cached under uncached on one baseline, cached up and uncached down from a centre line, or every bar full height split by hit rate. |
| counterStyle | "odometer" | "count" | "gauge" | "odometer" | The savings figure: rolling digit columns, a figure that counts through its values, or a figure over a gauge of the most the month could have saved. |
| accent | "cobalt" | "plum" | "mint" | "ink" | string | "cobalt" | The cached colour, the gauge and the selection; any CSS colour works. |
| disabled | boolean | false | Read only: the day cannot be scrubbed. |
| className | string | — | Classes for the panel, e.g. a max height; it scrolls inside its own box. |