Ladder
An LED ladder for levels and load: green, then amber, then red, the way a recording level has always been read.
Kit part · Charts
A bar chart built like a studio meter bridge: columns of LED segments behind a smoked window, green then amber then red, with a peak segment that lingers and a lit readout for the exact value.
Both finishes, side by side. Hover, pressed and focus are forced with .is-hover, .is-down and .is-focus; checked and disabled are real.
Aluminium
| Part | Rest · shows the highest | Hover a column | Focus a column | Peak held | Off the scale | No reading |
|---|---|---|---|---|---|---|
| Columns |
Graphite
| Part | Rest · shows the highest | Hover a column | Focus a column | Peak held | Off the scale | No reading |
|---|---|---|---|---|---|---|
| Columns |
| Name | Kind | Values | What it does |
|---|---|---|---|
| <tui-ledbars> | element | builds its own inside | The chart: a printed title, a lit readout, the scale, the smoked window with one column per reading, and the names. |
| values · labels | attribute | comma-separated | The readings and their names, in column order. Changing values animates; changing labels sets new columns. |
| label | attribute | required | Printed as the title and the name of the group: “Requests per minute”. |
| min · max | attribute | 0 · 100 | The scale. Values past it pin the bar at the end and say so in words. |
| warn · alarm | attribute | numbers in the scale’s units | Where the segments turn amber and red, and the wedges on the scale. Alarm under warn means low is bad (a battery, a budget). |
| lamp | attribute | "green" · "amber" · "red" · "blue" · "white" | The one colour when there is no warn or alarm. |
| segments | attribute | 4–60 · auto | Segments per bar. Auto picks 16–25 so each is a round amount: 0–2,000 in twenty of 100. |
| peak | attribute | boolean · "hold" | A peak segment that lingers 1.2 s at the last top, then falls; "hold" keeps it until resetPeaks() (the busiest minute of the hour). |
| unit · unit-text | attribute | "req/min" · "requests per minute" | The unit on the readout, and as it is read out. |
| decimals | attribute | auto from the range | Decimals on the readout and in the words. |
| orient | attribute | "vertical" · "horizontal" · "auto" | Columns stand up or lie down. Auto lies them down when the names do not fit under their columns. |
| label-every | attribute | auto | Print every nth name: 3 for the hours of a day. Auto thins the names only as much as they need. |
| active | attribute | column index | With .is-hover or .is-focus, the column those forced states show. |
| --tui-ledbars-led · --tui-ledbars-gap | CSS property | 5px · 2px | A segment’s length and the gap between segments: the chart’s height is segments × (led + gap). |
| --tui-ledbars-thick · --tui-ledbars-colgap | CSS property | 10px · auto | A lying bar’s width; the space between columns (auto: 30% of a channel, 2–6px). |
| .setData(values, labels?, { instant }) | method | numbers or { label, value } | New readings. Numbers keep the columns; pairs set new ones. instant skips the ballistics. |
| .resetPeaks() | method | — | Drop every held peak back to its bar. |
| .data · .active | property | array · index | The readings; the column the readout shows. |
| data-state | attribute | "running" · "asleep" | Written by the part: running only while a column moves. |
| Tab | keyboard | one stop | Enters the chart on the last column you were on, the first at the start. |
| ← → · ↑ ↓ · Home · End | keyboard | column to column | Move between columns; the readout shows the one with focus. |
| Point · touch | pointer | nearest column | The readout shows the column under the pointer or finger; leaving puts back the focused or the highest. |
| .is-hover · .is-focus | class | on <tui-ledbars>, with active | Forced states, for documentation and specimens only. |
<tui-ledbars label="Requests per minute" unit="req/min" unit-text="requests per minute"
min="0" max="2000" warn="1500" alarm="1800" peak
labels="api,auth,search,billing,queue,cdn,mail,db"
values="1284,1920,1610,420,880,1130,260,740"></tui-ledbars>
<!-- 24 hours, one colour, every third hour printed -->
<tui-ledbars label="kWh per hour · today" unit="kWh" min="0" max="4"
label-every="3" labels="00,01,02,…,23" values="0.42,0.38,…"></tui-ledbars>import '/kit/kit.mjs'; // defines <tui-ledbars>
const bars = document.querySelector('tui-ledbars');
// Same columns, new readings: they move with a meter's ballistics.
setInterval(async () => {
const perService = await fetch('/metrics/rpm').then((r) => r.json()); // { api: 1302, auth: 1710, … }
bars.setData(Object.values(perService));
}, 5000);
// New columns: pass { label, value } pairs.
bars.setData(steps.map((s) => ({ label: s.name, value: s.tokens })));Needs kit.css and kit.mjs. How to install the kit.
role="group" named by its label and described by one generated sentence: how many bars, the range, the highest and lowest, and who is over each line.role="meter" named by its label, with aria-valuenow, min, max and an aria-valuetext in words: “1,920 requests per minute, over the alarm line at 1,800”. They update with the data; browse through them to read the whole chart.A custom element that writes plain DOM: every segment is an <i> with its zone colour set once, and a frame only toggles is-on on the segments that changed. The lit layer is a pseudo-element with a hot centre and a glow in the segment’s own colour; unlit, the colour shows at 15% through the smoke. The window is the kit’s display glass with its glare fixed over the columns. Ballistics are two time constants (60 ms up, 420 ms down) and the peak holds 1.2 s then falls at 55% of the scale a second. The loop runs only while a column moves: it sleeps when every bar is on its reading, pauses off screen and in a hidden tab, and clamps a frame to 1/30 s. Names are measured on a canvas once per width, so thinning them costs no layout.
The window shows the shape; the readout and the words carry the numbers. Set the warning and alarm lines where the job says, not where they look good.
5 rules in this file, with the foundations they rest on and the anti-patterns that break them. Full rules ship in the brain with the Pass.
An LED ladder for levels and load: green, then amber, then red, the way a recording level has always been read.
Line charts drawn as light on glass, or as ink on a panel: gridlines faint, two traces at most, a red line for now.
A printed label over a value: key figures, with the unit small and the change in words.