Four application shells built from the registry: home, chat, studio and notebook
Four of the thirteen shipped application shells, captured from the live registry: home, chat, studio, notebook. One catalogue, four product frames.
Unlisted case study

Super AI Components

A component registry for AI applications. I designed a 109-item catalogue, tested my own organising principle against a board of real products, found it wrong, and shipped the re-cut version.

Design systemComponent catalogueAI product patterns0→1Open source

Vercel’s AI Elements is a shadcn registry for the conversation: message, reasoning, tool call, prompt input. It is good, and it stops where the conversation stops. Everything an AI product is around that (the launcher, the generation panel, the asset library, the node canvas, the permission prompt, the paywall) you build yourself, every time, from nothing.

Super AI Components is the other half. AI Elements gives you the conversation; this gives you the application. It installs the same way, composes with AI Elements rather than forking it, and is live today at super-ai-components.vercel.app.

Every screen below is a real capture from the live registry, a plate from the working Figma board, or a diagram of a decision that is written down in the repo. Nothing here was drawn for the case study.

Year
2026, ongoing
Role
Designer and system architect
Type
Open-source component registry
Catalogue
110 items, derived from real AI products
Shipped
130 installable registry items
Stack
React 19, TypeScript, Tailwind v4, shadcn registry

The first catalogue, and why it was wrong

The approved spec decomposed real AI products (ElevenLabs, Midjourney, Spline, Freepik, Topaz, Canva, Descript) into a 109-item catalogue, organised the way design systems for creative tools are usually organised: by modality. A writing kit, an image kit, an audio kit, a video kit, and a Flow Kit of 25 node types. It had a layer model, a token contract, and a wave-by-wave build order. It was approved and it was already being built.

Six weeks later I went back to the source material properly: a Figma board of screenshots from about thirty real AI products, organised by the two axes their authors actually used, app type (video editor, chat, flow builder, notebook, coding agent) and pattern type (first run, onboarding, global patterns, auth). Read against that board, the modality kits fell apart.

Writing, image, audio and video were four descriptions of the same three components with different content poured in. A tone selector and a shot-controls strip are one preset grid. A music brief and a brush-controls panel are one parameter panel. A video generation card is a result card in the streaming state. Organising by modality does not create the duplication, but it hides it, and then relies on discipline to avoid building it four times.

style-pickerpalette-pickertone-selectorshot-controlsmusic-briefbrush-controls
preset-grid + parameter-panel

Six kit-specific pickers are two components with different data poured in.

video-gen-cardgeneration-queuefailed-card
result-card states

A queue slot and a failed card are not components. They are states of the result.

text-nodellm-nodeimage-nodevideo-nodetts-nodesfx-nodemusic-nodecomposition-nodeasset-output-nodereference-node
ai-node, configured per type

Ten modality presets ship as demo recipes, not as ten registry items. The single largest saving in the re-cut.

Three of the collapses the re-cut forced. Nineteen named components in the approved spec resolve to three, and the difference is not economy for its own sake: each of the nineteen would have been a separate file to keep consistent.
The shipped result-card component with a control for stepping through its lifecycle states
The shipped result-card, carrying the states that the approved spec had named as separate components. Provenance travels with the asset (prompt, credits and seed on the card itself) so any surface showing the asset can show how it was made.

So I re-cut the catalogue along the board’s own axes and added one inclusion test that the first pass did not have:

A component earns registry status only if it appears in three or more unrelated products on the board. Anything appearing in one product is a demo, not a registry item.

The test is the useful part. It is falsifiable, it can be applied by someone who is not me, and it kills the failure mode a catalogue like this actually dies of: a hundred plausible components, each of which someone once saw somewhere. Sixteen entries from the approved spec failed it and were dropped: fourteen individual components and two whole groups. Twenty-eight items with no equivalent in the spec were added, including an entire first-run family the spec had no concept of. The total barely moved: 109 items became 110, composed differently.

The working board

The re-derivation is not an argument in a document, it is a board. Five columns, roughly 35,500 pixels tall: the catalogue as 110 compact tiles, the concept model, eight deep dives, then 109 detailed cards, one per component, each with a wireframe showing every state, three annotations covering the API decisions that matter, and one evidence line naming the products it was derived from. The fifth column is what the catalogue is missing.

The working FigJam board: five columns of component wireframes, concept model, deep dives, detailed cards and missing components
The top of the board. Left to right: catalogue tiles by family, the concept model, deep dives, full-detail cards, and the missing column in amber and green. Built in FigJam through the Figma MCP plugin API.

Two things came out of the concept model that changed the build, not just the drawings. The first is the promotion rule: layer-3 components may never depend on each other, so when two of them need the same piece, that piece moves up to a primitive rather than being imported sideways. Applying it surfaced five primitives that had been hiding inside leaf components.

Concept model plates: the L0 to L4 layer model, and the primitive fan-out showing which components consume each primitive
CM1 and CM2 from the board. The fan-out row length is the argument for a primitive existing. preview-tile has eleven consumers across six unrelated families, which is why it was the first thing to prototype: if its API does not hold across image, video, colour and text content, eleven components inherit the problem.
The shipped preview-tile component showing selected, loading, locked and failed states
preview-tile as shipped, with the states that made it load-bearing: selected drawn as a ring outside the element so selecting never reflows a grid, plus loading, locked and failed.

The second is that the four modality kits and the node canvas are the same loop drawn twice. Compose, generate, result, library, with saved assets returning as references in the next prompt. A node on a canvas is that loop collapsed into one card, and the edges between nodes are the loop drawn explicitly. That is why the Flow Kit needed nine components instead of twenty-five.

Concept model plates: the asset lifecycle loop and the cross-cutting contracts matrix
CM3 and CM4. The lifecycle loop is what a component has to sit on to earn its place; the contracts matrix is the second axis, binding six rules across fifteen families.

Contracts, not conventions

A hundred-component library where each component is individually reasonable still reads as a hundred libraries. What makes it one library is a small number of rules that cross every family, and the decision to enforce them mechanically rather than trusting future me to remember. Six of them: token, state, cost, provenance, empty, approval.

The cost contract is the one I would point at in a review. Money in AI products is not a billing page, it is a state that appears at the point of spend, and it takes exactly three forms: a chip on an action, a line before a commit, and a ring at the app level. Once that is written down, the paywall stops being a page someone designs in the last wave and becomes a state the generation button already has.

The run-button component showing its cost states: credits chip, insufficient credits, and plan-gated locked state
run-button carrying the cost contract: the estimate beside the action, the insufficient-credits state that names the shortfall, and the locked state where the gate is a plan rather than a balance. Three different problems, three different tells.

The empty contract came from a single observation on the board: NotebookLM ships three simultaneously empty panes on first load. An empty state is not an edge case in an AI product, it is the default view. The approved spec had no empty-state component at all, which means every component in the catalogue would have invented its own.

The empty-state component in its panel variant
One empty-state component with page, panel, in-grid and paired variants, so the first thing a user sees is designed once instead of eighty-four times.

The token contract is the one that is genuinely enforced rather than merely agreed: components style themselves from shadcn CSS variables only, no raw hex and no arbitrary Tailwind colour values, checked by a script that fails the build. It is why a component dropped into someone else’s app inherits their theme with no configuration, which is the entire promise of installing from a registry.

Auditing the method that produced the catalogue

The inclusion test has a hole in it, and it took a deliberate pass to find: a rule that discards single-occurrence patterns cannot tell the difference between rare and unsampled. The reference board is a creative-tools board. Every AI category absent from it was silently filtered out, and the test gave no signal that anything was missing.

So the last column of the board is thirty-two cards of what the catalogue does not have, colour-coded by how much I trust them. Green is recovered: seven components that were in the approved spec and that I dropped during consolidation without justifying it. The audio family was the worst of it, and the board’s own requirements table had named three of them. Amber is proposed and explicitly not validated, with a two-pixel border so the distinction survives at any zoom level.

The missing column: seven recovered omissions in green, each with a wireframe and the reason it was wrongly dropped
Recovered omissions. Each card names the error rather than the gap: env-status was dropped despite the spec pairing it with the credits ring, waveform-editor was collapsed into a track lane that cannot select a region, tts-composer was treated as a textarea with settings when it is a structured document.

The amber section is the more useful half. Five trust-and-control components had no representation in the catalogue at all, not because they are rare but because the board samples creative tools rather than agents with side effects. The most important missing component in the entire catalogue turned out to be a permission prompt: every tool-calling agent needs one, and it is a safety surface rather than a convenience.

The trust and control section of the missing column: permission-prompt, autonomy-selector, task-tray and safety-block, marked proposed
Proposed, not derived, and labelled as such. The honest version of a catalogue says which of its items are evidence and which are argument.

Those four shipped. The recommendation in the gaps document was not “add thirty-two components”. It was restore the seven recovered ones, add the two trust surfaces where absence is a defect rather than a scope decision, and go collect a second reference board before building the rest. That is what happened.

The shipped permission-prompt component: a scoped write action with deny, always allow, edit first and allow once
permission-prompt. Four verbs, and the arguments are inspectable before you approve them.
The shipped safety-block component showing a blocked request and a withheld response
safety-block. Input blocked and output withheld are different events and say different things.
The autonomy-selector component: ask every time, auto-approve reads, full auto, with standing permissions and a never-allowed list
autonomy-selector, the natural companion to the permission prompt: the standing grants are listed and individually revocable, and the never-allowed list is a separate thing from the not-yet-granted list.

What shipped

130 registry items are live and installable today: 116 components, 13 application shells and one headless hook, each fetched by URL through the standard shadcn CLI, with no package to depend on and no version to upgrade. The source lands in your repo and becomes yours.

npx shadcn@latest add https://super-ai-components.vercel.app/r/thread-list.json

Source: github.com/VV-DSGN-INC/Super-AI-Components

The shells are the part I would defend hardest. The board contained fourteen distinct layout archetypes, not the four the first catalogue assumed; thirteen of them are shipped as working frames rather than diagrams: the home launcher, the chat workspace, the studio editor, the three-pane notebook, the generation workspace, the library and explore galleries, the records and docs shells. The flow canvas shell is the one still outstanding.

The notebook shell: sources pane, chat pane and studio outputs pane
notebook-shell. Three panes, each independently empty-able, which is the observation that produced the empty contract in the first place, now enforced by the shell that made it.

Composition over reimplementation is the other rule that held. The registry never rebuilds what AI Elements or shadcn already ship; it references them as cross-registry dependencies so the CLI resolves the whole chain. To keep that honest I built a workbench of everything underneath first, all sixty shadcn primitives and all thirty AI Elements components on one theme, so that “does this already exist?” is a question with a place to look rather than a matter of memory.

The Storybook workbench showing the three layers: Super AI, AI Elements and shadcn
The Storybook workbench: the registry layer, the thirty AI Elements components it composes, and the sixty shadcn primitives underneath, all on one theme with a light and dark toggle.

Underneath the catalogue work, the thing that made a hundred-plus components survivable was treating the registry as a product with a test suite rather than a folder of files. The token contract is linted. Every stateful component has behaviour tests rather than markup snapshots. And the test that actually proves the product scaffolds a fresh app in CI, installs the built registry into it, and typechecks and builds the result, because a registry that looks right in its own docs site and fails on install is not a registry.

How it was built

I designed the catalogue, the layer model, the contracts and the per-component requirements; the implementation was executed by AI agents working against those specs, one wave at a time, in isolated branches, with me reviewing every wave before it merged. The board and the specification documents are not documentation written after the fact. They are the input the build ran from.

That working method is why the contracts matter more here than they would on a hand-built system. A rule that lives in a designer’s head does not survive parallel execution. A rule written into a spec, given a definition of done, and checked by a script does. The interesting shift is that the design work moved upstream: less time drawing the ninetieth component, more time on the inclusion test, the promotion rule and the contracts, the things that decide what the ninetieth component even is.

Reflection

What I would do differently. Sample the reference board before writing the catalogue, not after. The first 109 items were derived from products I already knew well, which is a perfectly good way to produce a catalogue that is confidently organised around the wrong axis. Six weeks of building happened against that structure before the board corrected it. The correction was cheap because shadcn components are copied rather than depended on, but that was luck about the distribution model, not foresight.

What surprised me. How much of the catalogue turned out to be states rather than components. Half the items I dropped were not redundant components, they were states that had been promoted to components because they had a name: a queue slot, a failed card, a locked panel. Naming a state convincingly is enough to make it look like a thing worth building.

What I would keep. The inclusion test, and writing down its limitation in the same repo. A catalogue is a series of claims about what is common, and the useful version tells you which of those claims are evidence and which are argument. The amber cards are the most valuable thing on the board, precisely because they are the ones I am least sure of.

Unlisted. This case study is reachable only by URL and is not indexed.