Pulliv0.1
8px
15 — Library

46 of 58, and what that does not mean.

Thirty-two more components, taking coverage from 24% to 79%. The inventory below is published in full so the figure can be audited rather than trusted — and the first section says plainly why a component count is a weak measure of readiness.

What 46 of 58 means

What genuinely improved

  • A team can now build most enterprise screens without leaving the system. That was not true at 14.
  • The dot-rail primitive extended to pagination, the nav rail and the timeline — each is options along a line, so none of them needed a new indicator invented for it. It extended to five of thirty-two on the first pass, which was not enough.
  • Every new component consumes semantic tokens only, works in both themes and all three densities, and has a forced-colors path.
  • The enterprise and regulated profiles cover the new components too — the loop indicators fall back where the conservative profile requires it.

What did not move at all

  • No npm package, no TypeScript, no React binding. Still not installable.
  • No Figma library. Designers still cannot use any of this.
  • No RTL. Logical properties were used throughout this batch, which helps — the earlier components still need converting.
  • No VPAT, no screen-reader test matrix. Every accessibility claim here is still unverified by testing.
  • Still unfunded. The question an enterprise asks first is whether this exists in three years.
Component count is a weak proxy for readiness, and worth saying out loud while raising it. Coverage went from 24% to 79%; the honest readiness assessment barely moved, because four of the six remaining blockers are engineering and organisational rather than design. A library of forty-six components that cannot be installed is not more adoptable than a library of fourteen that cannot be installed. The gap analysis is updated to reflect exactly this.

The derivation audit

Which components are actually kolam, and which are ordinary components wearing Tamil-named tokens. The deletion test, run on each of the forty-seven individually.

The first pass of this batch failed the test. Of the thirty-two components added, five carried the line and twenty-seven were conventional components consuming semantic tokens. That is the same failure as the original token layer — a kolam-shaped vocabulary wrapped around a system that would have looked identical without it — repeated one level down, in the components rather than the tokens. It was found by grepping the stylesheet for the primitive's four CSS signatures, not by reading the code, because reading your own code is how you miss this.

Three categories, not two

The binary "kolam or not" hid the interesting case. A component can carry a kolam mark that does no work — which is decoration, and worth admitting rather than counting.

Derived — 21

State or structure is carried by the line. Delete the kolam and the component loses information, not character. These are the ones that justify the source.

Ornamented — 3

Carries a kolam mark that carries nothing. Delete it and the component still works; only the flavour goes. Honest decoration, labelled as decoration.

Conventional — 23

A standard component consuming semantic tokens. There is no kolam in a scrim or a skeleton and inventing one would be worse than leaving it alone.

Per-component derivation audit
ComponentCategoryWhat the line does
CheckboxDerivedA pulli the line crosses — tile C, drawn at the moment of checking.
RadioDerivedAn open loop that closes. Dashed while unchosen, solid once wrapped.
SwitchDerivedA two-dot lattice at local pitch 3P; the loop travels from one dot to the other.
TabsDerivedThe dot rail. Options are pulli; the current one is wrapped.
Segmented controlDerivedThe dot rail, bounded.
StepperDerivedThe dot rail with completion — dots behind the head are joined by kambi.
TableDerivedColumn headers are pulli; the sorted one is wrapped, and the loop is the aria-sort state made visible.
ProgressDerivedKambi and pulli with a loop at the head — a line being drawn, which is what a kolam is.
Data gridDerivedThe table's language at scale, surviving virtualisation.
PaginationDerivedPages are pulli on a kambi; the current page is wrapped.
Nav railDerivedThe dot rail turned vertical.
TimelineDerivedThe dot rail with time as the axis; the current event is wrapped.
AccordionDerivedThe crossing losing an arm. Closed is tile C, open is the line passing.
Status dotDerivedA bare pulli. Escalation closes a loop around it, so severity is shape before it is colour.
SliderDerivedThe switch generalised past two stops. Same kambi, same pulli, same hollow loop with a dot inside.
BreadcrumbDerivedSeparators become the dots the line has already passed; the last crumb is where it turned, so that dot is wrapped.
MeterDerivedKambi and pulli with no head loop. That absence is now what separates a static reading from progress, instead of a colour.
Number stepperDerivedMinus is the line passing the dot; plus is the crossing. The two marks are the only two things a kolam line does.
File uploadDerivedDashed boundary while empty, solid once it holds a file — the radio's open-and-closed language at panel scale.
MenuDerivedA vertical list is options along a line, so a checked item gets a wrapped pulli rather than a tick.
TagDerivedA selected filter is a wrapped dot, so selection survives greyscale.
Card / panelOrnamentedFour corner pulli. They mark the corners of a lattice that is not there. Pure decoration.
Divider with labelOrnamentedA pulli where the rule meets the label. It marks a junction that carries no state.
Search fieldOrnamentedA loop with a line passing it — which is genuinely the primitive, and also just a magnifying glass. Coincidence dressed as derivation, so it is listed here rather than above.
Conventional — tokens only, and correctly so
Button · Text input · Select · Badge / chip · Callout · Button group · Split button · Icon button · Link · Toolbar · Form layout · Description list · Avatar · Code block · Stat · Banner · Spinner · Skeleton · Scrim · Drawer · Dialog · Tooltip · Popover

The seven rows marked in the margin were changed by this audit. Before it, the figure was 14 of 47 — 30%. After, 21 of 47 — 45%.

Why the number should not be higher

Forty-five percent is not an embarrassment to be fixed. A scrim is a translucent rectangle; a skeleton is a shimmering block; a tooltip is a small box near a thing. There is no kolam reading of these that is not a costume. The test each derived component passed is narrow and worth stating:

  • Is it options along a path? Tabs, pagination, breadcrumb, nav rail, timeline, menu, slider, stepper. The kolam line visits dots in order; so do these.
  • Is it a thing that opens and closes? Radio, checkbox, accordion, file upload, tag, status. The line either wraps a dot or passes it, and there is no third option.
  • Is it a line in motion, or a line at rest? Progress and meter. Once that distinction is carried by the presence of a head loop, the two components stop needing different colours to be told apart.

Everything that failed all three was left alone. Forcing the language onto a dialog would have produced exactly the thing you objected to two rounds ago: kolam as a skin.

The deletion test, applied to this page. Remove the kolam from the twenty-three conventional components and nothing is lost. Remove it from the twenty-one derived ones and the system loses its greyscale-safe state language, its distinction between progress and meter, its sort indicator, and every selected state that currently survives Windows High Contrast Mode without a colour. That asymmetry is the whole argument, and it is why the ratio is published rather than the headline.

The inventory

The reference list the coverage figure is measured against. Shipped · Partial · Absent. Published so an evaluator can disagree with the denominator.

Actions — 6

  1. Buttonshipped
  2. Button groupshipped
  3. Split buttonshipped
  4. Icon buttonshipped
  5. Linkshipped
  6. Toolbarshipped

Forms — 14

  1. Text fieldshipped
  2. Textareashipped
  3. Selectshipped
  4. Checkboxshipped
  5. Radioshipped
  6. Switchshipped
  7. Number inputshipped
  8. Search fieldshipped
  9. Slidershipped
  10. File uploadshipped
  11. Form layoutshipped
  12. Comboboxabsent
  13. Multiselectabsent
  14. Date pickerabsent

Navigation — 8

  1. Tabsshipped
  2. Steppershipped
  3. Breadcrumbshipped
  4. Paginationshipped
  5. Menupartial
  6. Nav railshipped
  7. Tree viewabsent
  8. Command paletteabsent

Data display — 12

  1. Tableshipped
  2. Data gridread-heavy
  3. Description listshipped
  4. Avatarshipped
  5. Tag / chipshipped
  6. Badgeshipped
  7. Status dotshipped
  8. Metershipped
  9. Code blockshipped
  10. Timelineshipped
  11. Stat / KPIshipped
  12. Chartsabsent

Feedback — 9

  1. Alertshipped
  2. Toastshipped
  3. Bannershipped
  4. Progressshipped
  5. Spinnershipped
  6. Skeletonshipped
  7. Empty stateshipped
  8. Inline validationshipped
  9. Notification centreabsent

Overlays — 6

  1. Modalshipped
  2. Confirm dialogshipped
  3. Drawershipped
  4. Popoverpartial
  5. Tooltippartial
  6. Sheet — mobileabsent

Layout — 3

  1. Cardshipped
  2. Dividershipped
  3. Accordionshipped
Counting rule. Partial does not count toward the headline figure — the conservative reading is the honest one. 46 shipped + 4 partial + 8 absent = 58. The headline is therefore 46 of 58 = 79% fully shipped, or 86% if you allow the partials, which this page does not.

The four partials each name their limit: the data grid has no cell editing, grouping or server-side data; the menu, popover and tooltip use naive viewport-flip placement rather than Floating UI, so they will misplace inside scrolling containers or transformed ancestors. The eight absent are combobox, multiselect, date picker, tree view, command palette, charts, notification centre and the mobile sheet.

This callout originally claimed "46 shipped + 4 partial = 46", which is wrong by four. The audit script that checks the table against the headline caught it — which is the argument for publishing the inventory in a machine-checkable form rather than asserting a percentage.

Actions

A link External
group joins on one hairline · split shares a boundary · icon button floors at 44px · toolbar is one tab stop, arrows inside

Forms

Position
6%
Supporting documents

Drop files here, or

    fieldset + legend · form-row auto-fits at 26P · number steppers are 44px targets · dropzone accepts drag and click

    Data display

    Provisioned 4.82 PB ▲ 3.1% vs last month
    Pool utilisation71%
    POOL-0794%
    meter is a measurement, progress is a task — kept distinct on purpose
    SKRNMP +3
    Operational Breaching
    Flash Archive EMEA
    Tier
    Flash
    Capacity
    412 TB
    Replication
    Synchronous
    status dot: colour reinforces, the label carries it · off-scale gets a ring so it reads without colour
    1. 09:12
      Threshold crossed — POOL-07 at 90%
    2. 09:14
      Alert raised to storage on-call
    3. 09:31
      Reclaim job queued — 41 TB identified
    4. —
      Awaiting approval
    timeline: the dot rail with time as the axis · the current event is wrapped

    Feedback

    Loading positions…
    spinner is plain, not a kolam — enterprise needs a loader that is not an expressive asset · skeleton has no shimmer, because a looping animation is what the motion rules forbid

    Overlays

    focus moves in, is trapped, and is restored to the trigger · Escape always closes
    Placement is the naive version. Menus, popovers and tooltips flip against the viewport edge and clamp horizontally. They do not handle scrolling containers, transformed ancestors, or shift-with-scroll. That is why they are marked partial — a production system should use Floating UI here, and swapping it in is a contained change because placement is one function.

    Layout

    Advanced
    Synchronous within region, asynchronous cross-region with a 15-minute recovery point objective.
    the disclosure mark is the crossing tile losing an arm — closed is a crossing, open is the line passing straight through