← Biblioteca CLAUDE.md CatálogoContratoLeia-me
contrato

Contrato da biblioteca

Leia este arquivo inteiro antes de extrair, alterar ou consumir qualquer componente. Ele existe para que todo site novo saia com a mesma lógica de HTML, CSS e JS. Regra de ouro: antes de inventar um componente, procure no catalogo.json.


1. Stack fixa

Camada Decisão Não use
Markup HTML semântico estático template engine, JSX
Estilo CSS puro, custom properties Tailwind, SCSS, CSS-in-JS
Script JS vanilla, ES5-safe, dentro de IIFE jQuery, bundler, imports
Libs nenhuma por padrão GSAP só quando a ficha declarar
Fontes @font-face local, woff2 + woff Google Fonts em produção

O alvo é um snippet que cola em três lugares sem adaptação: página estática, .astro, ou bloco HTML do Elementor. Qualquer coisa que quebre isso está fora do contrato.

GSAP só entra quando a interação depende de timeline encadeada ou de ScrollTrigger com scrub. Reveal, parallax simples e entrada de seção são IntersectionObserver + requestAnimationFrame — já resolvidos no core/motion.js, não reimplemente.


2. Idioma

Motivo: o código já roda assim nos sites existentes (Tarvos, Liberta Wealth). Trocar agora quebraria a portabilidade nos dois sentidos.


3. Tokens — a interface do componente

Componente nunca escreve cor, fonte, espaçamento de seção ou curva de easing na mão. Só lê token. Isso é o que permite o mesmo hero rodar preto-e-sage na Liberta e claro-e-glow em outro cliente.

Tokens globais (definidos em core/tokens.css)

--display        família de títulos
--sans           família de texto
--pad            respiro lateral da coluna
--max            largura máxima da coluna
--nav-h          altura do menu fixo
--sec-gap        respiro vertical entre dobras
--ease           curva única do projeto
--radius-pill    raio de botão (1000px)
--radius-media   raio de imagem/card (0 em projeto flat)
--accent         cor de marca
--accent-2       cor de marca secundária

Tokens de escopo de tom (definidos pela classe da seção)

--bg             fundo da seção
--fg             texto principal
--fg-2           texto secundário
--fg-muted       texto de apoio / legenda
--rule           linha divisória fraca
--rule-2         linha divisória forte

Escopos disponíveis: .sec-dark, .sec-deep, .sec-paper, .sec-light. A seção declara o escopo; os componentes dentro dela herdam. Um componente jamais faz override de --fg por conta própria.

Regra do tom vizinho

Fundos escuros adjacentes têm de ser quase idênticos (#0a0a0a / #131313). Salto forte de tom entre seções suja a página. Se precisar de contraste real, use uma seção .sec-paper inteira como respiro, e a seguinte volta direto ao escuro.


4. Grid

.wrap é a única regra que controla a coluna:

.wrap{width:100%;max-width:var(--max);margin-inline:auto;padding-inline:var(--pad)}

Nenhum componente mexe em padding-inline, max-width de página ou margin lateral. Precisa sangrar até a borda? O elemento sai de dentro do .wrap, não ganha margin negativa.

Ritmo vertical: .sec-pad (padding: var(--sec-gap) 0). Não invente clamp solto para separar seções.


5. Movimento

Três ganchos globais, servidos por core/motion.js. Componente usa esses — não escreve observer próprio para entrada de elemento.

Gancho Uso Efeito
data-rv qualquer bloco fade + blur + subida
data-d="1..3" junto do data-rv escalona o delay
data-split frase de destaque revela palavra a palavra
.ttl título de seção reveal próprio, com blur

Nada entra seco. Toda entrada carrega filter: blur(14px) indo a zero. Translate puro não é aceito.

prefers-reduced-motion: reduce desliga tudo — já tratado no core. ?motion=on na URL força a animação para gravar vídeo ou apresentar.


6. Regras de CSS por componente

  1. Um prefixo, sempre. Todas as classes do componente começam pelo prefixo declarado no componente.json (hero-, fan-, marquee-). Nada de .n, .full, .veil soltos — colidem no primeiro projeto que juntar dois componentes.
  2. Zero !important. Se precisou, o token está errado.
  3. Zero seletor de elemento global. Um h3 dentro do componente vira .fan-title.
  4. Nenhuma dependência de ordem de carregamento. O CSS do componente funciona colado em qualquer posição da folha.
  5. Mobile no fim. Media queries de largura ficam no fim do próprio bloco, nunca em arquivo separado. @media(prefers-reduced-motion) é exceção e fica colado na regra que desliga — ali a proximidade é o que torna a intenção legível.

Quem confere isso é o bin/conformidade.py, que audita cada componente contra este arquivo: prefixo, !important, seletor de elemento, cor crua, ordem das media queries, IIFE, passive, movimento reduzido. Rode antes de dar um componente por pronto:

python bin/conformidade.py

Um alerta pode ter explicação legítima — e quando tem, ela vira comentário no próprio arquivo, para o próximo a passar por ali não precisar redescobrir.

Primitivas do core

O componente pode assumir que estas existem e não as recopia:

Classe O quê
.wrap a coluna
.sec-pad respiro vertical da seção
.eyebrow olho com traço
.btn / .btn-primary / .btn-ghost botão pílula
.grain ruído SVG sobre mídia escura
.glass / .glass-hover card de vidro (borda tênue, brilho radial, blur)
h2.sec-title / .sec-lead título e apoio de seção
.sec-head cabeçalho de dobra centralizado; largura por --head-max
.pill / .pill-accent rótulo pequeno em pílula de contorno

Uma regra que aparece em três ou mais componentes é candidata a primitiva. Antes de recopiar pela terceira vez, promova ao core e ajuste os componentes.

Véu sobre imagem

backdrop-filter em caixa reta produz borda dura e lê "chapado". Sempre acompanhado de máscara em gradiente:

mask-image:linear-gradient(to top,#000 0%,rgba(0,0,0,.9) 44%,transparent 100%);

Texto sobre imagem

Legenda ou título de card de mídia vai dentro da imagem, ancorado embaixo, com gradiente mais blur mascarado. Não vira parágrafo abaixo da foto.


7. Regras de JS por componente

(function () {
  var root = document.querySelector('.meu-componente');
  if (!root) return;                                        // guard
  addEventListener('scroll', onScroll, { passive: true });   // sempre passive
})();
  1. IIFE fechada. Nada no escopo global.
  2. Guard clause. Ausência do elemento é saída silenciosa, nunca erro no console.
  3. passive: true em scroll e resize.
  4. requestAnimationFrame para qualquer coisa presa ao scroll — nunca cálculo direto no listener.
  5. Respeita reduce. Leia a flag do core antes de animar.
  6. Sem busca global no documento quando o componente pode repetir na página: parta da raiz do próprio componente.

8. Anatomia de um componente

componentes/<categoria>/<nome-kebab>/
├── componente.json   metadados lidos pelo índice
├── ficha.md          o que é, quando usar, padrão editorial, histórico, gotchas
├── markup.html       só o bloco da seção, sem <html> nem <head>
├── estilo.css        só as classes do prefixo
├── script.js         opcional — ausente se for CSS puro
└── preview.html      página autônoma que roda o componente sozinho

preview.html importa o core/ por caminho relativo e usa os placeholders de showroom/demo/. Ele tem de abrir com duplo-clique, sem servidor.

O preview.html é gerado a partir do markup.html — nunca escreva o markup duas vezes à mão:

bash bin/previews.sh                          # todos
bash bin/previews.sh hero/full-bleed-media    # um só
TEMA=<projeto> bash bin/previews.sh           # com outro tema

Precisa de mais que o markup no preview? Três arquivos opcionais na pasta do componente, todos respeitados pelo gerador:

Arquivo Para quê
preview-extra.html markup depois do componente — uma seção falsa para o parallax ter para onde rolar, um botão que dispara o estado
preview-css.txt folhas extras, um caminho por linha — para componente que compõe outro
preview-js.txt scripts extras, um por linha, inseridos antes do próprio

9. Fluxo para catalogar um componente novo

  1. Copie _modelo/ para componentes/<categoria>/<nome>/.
  2. Extraia o markup do projeto de origem e normalize os prefixos de classe.
  3. Troque toda cor crua por token. Se faltar token, discuta antes de criar — token novo é decisão de arquitetura.
  4. Se a regra já apareceu em três componentes, promova ao core como primitiva antes de recopiar.
  5. Preencha componente.json e a ficha.md inteira, inclusive o padrão editorial (que conteúdo entra ali) e o histórico.
  6. Registre em projetos/<projeto>.md de onde veio.
  7. Rode os dois geradores:
python bin/indice.py        # catalogo.json + tabelas do CATALOGO.md + cards do showroom + fichas em HTML
bash bin/previews.sh        # preview.html de cada componente, a partir do markup.html
python bin/conformidade.py  # audita o componente contra este contrato
python bin/valida.py        # confere que nenhum caminho relativo aponta para o vazio

catalogo.json, as tabelas do CATALOGO.md, os cards do showroom e os preview.html são gerados. Editar qualquer um deles à mão é trabalho perdido na próxima execução — a fonte é o componente.json e o markup.html.


10. Fluxo para consumir num site novo

  1. Leia o CATALOGO.md e escolha as seções.
  2. Copie core/tokens.css, base.css, motion.css e motion.js.
  3. Duplique core/temas/_modelo.css para o tema do cliente e preencha só os valores.
  4. Cole markup.html, estilo.css e script.js de cada componente escolhido.
  5. Nunca edite o componente para caber no cliente — edite o tema. Se o tema não resolve, o componente precisa de uma variação nova na ficha, não de um hack local.

11. Status possíveis

Um externo que roda num site vira estavel (ou revisar, se deixar pendência) — e a ficha registra em qual projeto isso aconteceu. Essa promoção é o único caminho de saída do externo.

Componente de origem externa

Componente que veio de fora entra sempre como externo, e a ficha tem de trazer, no histórico: de onde veio, quem escreveu, sob qual licença. Mesmo licença permissiva costuma exigir crédito — e crédito não custa nada. Se a licença não estiver clara, não catalogue: reescreva do zero ou deixe passar.