Contacto
Gabs

Caso de estudo de Gabriel Espinheira, engenheiro full-stack sénior

Fabricator UI, shadcn/ui com personalidade própria

Uma biblioteca de componentes React open source que se instala com o CLI do shadcn/ui em projetos que já o usam, com uma linguagem de design própria. Construí-a a dirigir agentes de programação: primeiro commit a 05/10/2026, o CLI no npm como 0.2.1 a 11/10/2026.

Ainda no início: versão 0.3.0, servida a partir do site da documentação.

O que o repositório diz

5.120

itens do registo comparados com ui.shadcn.com em cada push

27

builds de cada componente: 3 primitivas, 9 estilos

62

componentes na documentação

61

ficheiros de estilo que fazem o visual Fabricator

32

sons de interface, sintetizados no browser

5

cenários de instalação construídos de raiz no CI

Contado a partir do repositório a 10/10/2026, no commit a025e94, e da sua execução de CI de 09/10/2026.

Visual próprio, nada para migrar

O shadcn/ui dá às equipas React os seus componentes como código-fonte, através de um CLI e de registos que qualquer pessoa pode publicar. Para dar a uma biblioteca um visual próprio, podia fazer fork desses componentes ou publicar um pacote que ninguém consegue editar, e os dois afastam-se do original.

Queria uma terceira opção: um visual e um movimento próprios, instalados com os comandos que um projeto shadcn/ui já usa, com cada nova versão do original ainda fácil de juntar. Eis de quem é cada parte do trabalho, tudo sob a licença MIT:

shadcn/ui
o código dos componentes para três bibliotecas de primitivas, oito estilos, o motor do CLI e a app de documentação de onde partiu
Fluid Functionalism
a linguagem de design de Micka Touillaud: superfícies, movimento, hover fluido e barras de scroll
Meu
a camada de registo, o estilo Fabricator e as suas substituições, os tokens, os sons e a Pesquisa, o wrapper do CLI, os testes de paridade e de instalação, e o site

Os mesmos componentes, outra sensação

O site da documentação mostra o estilo Fabricator, por isso mostra o que uma instalação lhe dá. Cada filme abaixo é uma gravação do site ao vivo a 11/10/2026.

01

Um destaque que desliza

Em menus, separadores, barras laterais e tabelas, um destaque salta com uma mola para o item mais próximo do cursor, por isso uma lista nunca pisca de linha em linha e um clique num espaço vazio cai no item destacado. O foco do teclado move o mesmo destaque. Mede os itens pelas suas posições no layout, por isso um popup que ainda está a crescer não o engana, e corre em molas CSS sem biblioteca de animação. Doze componentes usam-no em Base UI e Radix, dez em React Aria.

02

Oito superfícies, uma cor

Cada superfície é um fundo e uma sombra, sem margens: o anel de 1px da sombra desenha o contorno. Uma cor base, guardada em duas variáveis CSS, dá tom aos oito níveis em modo claro e escuro. O modo claro baixa a luminosidade de cada nível à medida que o tom cresce, porque a cor precisa de espaço abaixo do branco, e os testes verificam que cada nível fica em sRGB e que cada par de texto fica AA em toda a roda de cores.

03

Uma API sobre três bibliotecas de primitivas

Cada componente tem uma árvore de código para Base UI, Radix e React Aria, com os mesmos nomes, props, variantes e atributos data-slot em cada uma. Mudar a documentação entre elas troca a primitiva por baixo e deixa o componente com o mesmo aspeto. Uma alteração numa árvore chega às três na mesma alteração, e um componente que substitui um do shadcn/ui só acrescenta à sua API.

A página Motion da documentação: três velocidades de mola, rápida, moderada e lenta, cada uma com os tempos de entrada e de saída e um ponto para a reproduzir.
04

Movimento em três molas

Cada transição escolhe um de três níveis: 90 ms para hover e popups, 210 ms para seleções e painéis, e 290 ms com um ligeiro ressalto para diálogos. As saídas são cerca de um quarto mais rápidas. Os componentes nunca escrevem milissegundos, por isso uma só variável de escala acelera, abranda ou para todas as animações, e o movimento reduzido mantém os desvanecimentos e tira as deslocações.

A página Sounds da documentação: o catálogo, um material por família de componentes, por cima de uma tabela de sons para tocar com as durações e os tons.
05

Sons sem ficheiros de áudio

Trinta e dois sons de interface são sintetizados no browser com a Web Audio API, cada um alguns tons curtos ou um sopro de ruído filtrado. Cada família de componentes tem o seu material: os botões soam a madeira e os separadores tocam como sinos afinados num acorde. Um componente toca-os a partir de atributos que os componentes já têm, e ficam desligados até alguém os ligar. O catálogo segue a lista publicada por Bencho de funções e tons; a síntese é original.

Placeholders à entrada, estilos à saída

O código de um componente mantém a estrutura e o comportamento no próprio sítio e nomeia tudo o que um estilo pode mudar com uma classe placeholder, como cn-button-variant-outline. Um mapa de estilos transforma cada placeholder em classes Tailwind durante a build. É o próprio modelo do shadcn/ui, e o visual Fabricator é mais um mapa de estilos: 61 ficheiros CSS, um por componente.

Uma só build compila todas as bibliotecas de primitivas em todos os estilos e serve o resultado em dois endereços. O modo Blend compila os componentes extra no estilo que o projeto já usa; o modo Fabricator serve o visual Fabricator completo. O comportamento que o CSS não consegue exprimir, como o Fluid Hover, vive em 48 substituições que só compilam no estilo Fabricator, para que os estilos originais mantenham exatamente o mesmo resultado.

A maioria dos redesigns é uma alteração de CSS.
  • Base UI
  • Radix
  • React Aria

Código dos componentes com placeholders

Mapas de estilos · 8 originais, 1 Fabricator

Build do registo · 27 combinações

Modo Blend · o seu estilo

Modo Fabricator · o seu visual

O CLI do shadcn no seu projeto

Regras que o mantêm encaixável

Um projeto em shadcn/ui deve aceitar um componente Fabricator sem mudar o seu próprio código. As instruções do repositório chamam a estas regras o contrato: uma alteração que quebre uma delas é um erro, mesmo que tudo compile.

Só acrescentar

Um componente que substitui um do shadcn/ui mantém todos os nomes, props, variantes, exports e data-slots. Props e variantes novas são acréscimos opcionais.

Um id de estilo válido, sempre

O components.json mantém um id de estilo original, como base-nova. Um id próprio faria falhar contra ui.shadcn.com todos os shadcn add simples do projeto, por isso o visual Fabricator viaja no endereço do registo.

Dependências com namespace

Os itens Fabricator dependem uns dos outros como @fabricator/nome. Um nome simples refere-se sempre ao item do próprio shadcn/ui, e só se escreve quando essa é a intenção.

O contrato dos tokens

Todas as variáveis CSS do shadcn/ui mantêm o nome e o significado, para que o tema de um projeto passe para lá. Os tokens Fabricator chegam com nomes novos, dentro dos itens que os usam.

Três árvores, uma alteração

Uma alteração ao código de uma biblioteca de primitivas chega às outras duas na mesma alteração, e uma exceção deliberada di-lo no commit.

Reconstruído, nunca editado à mão

Os índices, o mapa de estilos montado e o registo compilado são reconstruídos a partir do código. O código original só entra através de um script de sincronização, num ramo próprio.

A página inicial do Fabricator UI em modo escuro: versão 0.2.1, o título Components that move with you, filtros por categoria e as primeiras demonstrações ao vivo: um menu, separadores e interruptores.
A página inicial é uma galeria de todos os componentes, cada um na versão Fabricator compilada que uma instalação escreveria.

As verificações que cada alteração tem de passar

O CI corre em cada pull request e em cada push para o main: uma build completa do registo, lint, tipos e formatação, os testes unitários, a paridade com o original e depois uma build de produção do site e os testes de instalação. Tudo passou no main a 09/10/2026.

Paridade com o original

Cada push compara 5.120 ficheiros compilados do registo com ui.shadcn.com. Tirando o conteúdo de demonstração com nova marca e os itens próprios do Fabricator, coincidem byte a byte, e três correções de erros ficam registadas como exceções deliberadas.

Instalações construídas de raiz

O CLI prepara apps Vite nas três bibliotecas de primitivas, uma app Next.js e um projeto shadcn/ui existente, instala componentes em cada um a partir do registo servido localmente e corre uma build de produção de todos.

Contraste como teste unitário

As cores de estado, a escada de superfícies e o tom são testados para WCAG AA em claro e escuro, o tom em toda a roda de cores na intensidade máxima, para que uma nova cor não saia com texto abaixo de 4,5:1.

Uma build que encravou sem um erro

Na máquina de build normal de 8 GB da Vercel, a build do site era terminada por falta de memória sem mensagem, e as publicações ficavam em Building até serem canceladas. Reproduzi o problema num contentor com os mesmos limites, baixei a build para 7 GB e escrevi o orçamento nas regras do repositório para todos os agentes.

A maioria das linhas é do shadcn

O Fabricator UI parte do repositório do shadcn/ui num commit fixo, e a maioria das suas linhas continua a ser do shadcn, sem alterações. É de propósito: quanto menos ficheiros originais edito, mais barato é juntar a próxima versão do original, por isso o meu trabalho vai para ficheiros novos sempre que possível.

Todos os commits têm o meu nome, e o trabalho aconteceu em sessões de agentes: 23 dos 27 commits creditam o Claude como coautor, e os meus registos locais têm 14 sessões do Claude Code e 15 do Codex no repositório. O PLAN.md regista 13 decisões de arquitetura, e as regras dizem a todos os agentes para o lerem antes de mexer no registo ou no CLI.

Ainda é cedo. O CLI chegou ao npm como 0.2.1 a 11/10/2026, e o registo é servido a partir do site da documentação na Vercel até fabricator-ui.com estar no ar. Os filmes desta página foram compostos e renderizados no Relay, a partir de gravações do site ao vivo.

Linhas não vazias de cada ficheiro do repositório no commit a025e94, por origem do ficheiro.
Linhas não vazias de cada ficheiro do repositório no commit a025e94, por origem do ficheiro.
OrigemLinhasPercentagem
Do shadcn/ui, sem alterações301 94057%
Do shadcn/ui, editado164 21831%
Gerado pela build20 6714%
Acrescentado para o Fabricator UI43 5628%

Os ficheiros editados mudaram com 19.607 linhas acrescentadas e 12.264 removidas, sobretudo conteúdo de demonstração com nova marca. 48 dos ficheiros acrescentados são substituições: cópias de componentes do shadcn/ui com comportamento Fabricator acrescentado.

Uma decisão difícil: tornar-se um registo

Problema

Uma biblioteca com visual e componentes próprios tinha de funcionar nos projetos que as pessoas já têm e acompanhar um original que avança depressa. Entre março e setembro de 2026, o shadcn/ui lançou uma nova versão principal do CLI, uma nova biblioteca de primitivas por defeito e um novo pacote para juntar classes.

Opções

Fazer fork dos componentes e do CLI dá controlo total, mas cada nova versão do original passa a ser uma migração manual, e os projetos existentes não conseguem acrescentar um componente com os comandos que já usam. Um pacote npm em runtime mantém o código num só sítio e tira o código-fonte que as pessoas esperam ter.

Escolha

Tornar-se um registo que o CLI oficial já entende. Um CLI fino com marca própria corre o pacote shadcn fixado e acrescenta as suas predefinições. O código mantém o modelo de placeholders do shadcn, por isso o design é mais um mapa de estilos, o original chega num ramo próprio através de um script de sincronização, e cada push prova que os itens originais continuam iguais a ui.shadcn.com.

Custo

O Fabricator UI fica preso ao contrato do shadcn: nenhuma prop nem token com nome mudado e nenhum id de estilo próprio, por isso o seu visual tem de viajar no endereço do registo. Cada item é construído 27 vezes, e os fragmentos de componentes para cada estilo original fizeram parte do que levou a build do site para lá dos 8 GB da Vercel.

Uma decisão mais pequena: construir o site no meu portátil

A build da Vercel levava sete a nove minutos e a maior parte da memória; o portátil constrói e envia em menos de quatro. O script de publicação envia o resultado final, cerca de 48.000 ficheiros, num só arquivo, porque a Vercel aceita 15.000 por envio. O custo é que as publicações dependem de uma máquina, por isso as publicações em produção recusam-se a correr a partir de algo que não seja um main limpo igual ao GitHub.