O i18n cuida da tradução.
O KDF cuida do seu design.
E os dois vivem no JSON.
Uma camada de coordenação de design em JSON focada em web apps SSR (server-side) e UIs feitas com a ajuda de agentes. Decisões que se repetem — layout, espaçamento, tipografia, estilos de componentes — vivem em uma única fonte da verdade que seus agentes leem de forma clara, sem precisar caçar estilos perdidos por arquivos, páginas e sessões.
{ "$layout": ["hero", "footer"], "hero": { "wrapper": "mx-auto max-w-6xl px-6 py-20", "title": "@typography.h1", "cta-primary": "@button.cta" } }
Uma única fonte da verdade mantém cada página, componente e sessão dos agentes totalmente consistentes.
O JSON define · o código renderiza · data-kdf faz o mapeamento inverso
O design começa a se
perder nos componentes.
Quando os nomes de classes vivem só dentro de arquivos .tsx, cada página começa a divergir aos poucos. Pra um humano mantendo tudo sozinho até funciona — mas o negócio quebra assim que os agentes começam a mexer na interface.
<section className="mx-auto max-w-6xl px-6 py-20"> <h1 className="text-5xl font-semibold tracking-tight"> // …and again, slightly different, on the next page
O mesmo botão ganha silenciosamente cinco variantes. O espaçamento muda de uma página pra outra. Cada nova sessão do agente precisa redescobrir as regras do zero.
- — Os agentes improvisam cores, espaçamento, tipografia e layout.
- — Os usuários ficam corrigindo os resultados pelo chat o tempo todo.
- — Mudar algo significa ter que caçar os estilos no meio dos arquivos de componentes.
- — As sessões antigas não repassam a intenção do design para as novas.
→ iteração "maior" · "mais azul" · "um pouco pra esquerda" infinita
Torne o design explícito.
O KDF faz pelo design o mesmo que o i18n faz pelo texto: ele tira decisões repetitivas dos arquivos de componentes e as coloca no JSON. A interface renderizada ainda usa CSS normal — a diferença é quem controla isso.
{ "hero": { "title": "text-5xl font-semibold tracking-tight" } }
const d = getDesign("homepage"); <h1 data-kdf="hero.title" className={d("hero.title")}>
Uma biblioteca diz 'o que'.
O KDF diz qual.
Uma biblioteca de design te entrega um Botão. O KDF diz que isso é o homepage.hero.cta-primary, renderizado como um Botão, e com esse token de estilo. Ele adiciona o mapeamento que falta nas bibliotecas — conectando o elemento direto à decisão de design.
Seis símbolos.
Uma gramática.
O KDF armazena nomes de classes, referências compartilhadas, a ordem das seções e CSS custom properties. Ele nunca guarda lógica de negócio, event handlers, chamadas a APIs, permissões ou comportamento de acessibilidade.
Todo elemento que usa um token carrega o caminho de onde ele veio. Os nós do DOM apontam de volta pro JSON — excelente pra scanners, testes e pros próprios agentes.
Resolve um caminho pra retornar a string className. Já o d.css() retorna um objeto de CSS custom properties.
Aponta para um token reutilizável dentro de shared/. Refs podem encadear e estender com classes extras.
Um array de chaves de seções. As listadas são renderizadas na ordem; se faltar alguma, o app esconde.
Metadados pros agentes e pro host — qual componente vai renderizar aquele token, junto com dicas de variantes e tamanho.
Valores que não cabem como classes reutilizáveis são aplicados como variáveis de estilo inline usando o d.css().
Padrões compartilhados.
Overrides por página.
Os design tokens vivem em dois lugares: padrões reutilizáveis no shared/, e uma composição por página pra sobrescrever só o necessário. Dois arquivos CSS sob seu controle cuidam do first paint e servem de rota de fuga.
kdf/ shared/ button.json ← reusable defaults card.json color.json typography.json homepage.json ← page composition konde-server.css ← critical, first paint konde.css ← non-critical tweaks
Uma referência como @button.cta é resolvida primeiro no shared/ da página, depois no shared/ pai, e depois nos tokens da página. O template sobrescreve só o que precisa e herda o restante.
O design é resolvido no backend; o navegador já recebe a string de classes pronta. O CSS crítico carrega logo no first paint, e o restante depois — sem jogar processamento de renderização nas costas de celulares mais fracos.
Importado pelo app pra que variáveis de design e regras anti-FOUC (pra não piscar o estilo) carreguem antes de tudo.
/* konde-server.css */ :root { --kdf-primary: #1F8F47; } [data-kdf="hero.slider"] { display: none; }
Carrega depois dos frameworks pra você ajustar o que quiser sem travar a renderização inicial da página.
/* konde.css */ [data-kdf="hero.title"] { letter-spacing: -0.02em; } [data-kdf="hero.wrapper"] { gap: 3rem; }
→ O KDF só cria isso uma vez e nunca sobrescreve. Você só precisa importar; o plugin te dá o caminho pela env.
Mude de design
como se muda de idioma.
Da mesma forma que o i18n troca idiomas, o KDF troca templates de design. É o mesmo app, os mesmos componentes, o mesmo código — você só aponta a variável KDF_DIR para outra pasta e o visual muda por completo.
designs/ lander/ shared/ homepage.json newlander/ shared/ homepage.json
// next.config.ts withKDF({ dir: "./designs/lander" })(nextConfig);
Resolve no servidor.
Passa as strings pro cliente.
O KDF lê o JSON no disco, então ele roda totalmente no backend: Next.js (Server Components), Astro, Hono. Resolva as classes lá e entregue as strings puras pro frontend.
import { getDesign, cn } from "@kondeio/kdf"; const d = getDesign("homepage"); <button data-kdf="hero.cta" className={cn(d("hero.cta"), isActive)}>Start</button>
→ string de className resolvida
→ objeto de custom-properties de CSS
Junte classes condicionais, limpe nulos, remova duplicadas — sem inventar semântica por padrão.
No ambiente de produção, faz cache. No ambiente de desenvolvimento, revalida por mtime & tamanho.
Fica uma camada
acima da sua stack.
ESTILIZAÇÃO — GUARDA NOMES DE CLASSES, NÃO CSS
O KDF não é uma engine de CSS. Os tokens só guardam o que quer que seu sistema de estilo entenda. Se o seu framework varre arquivos-fonte atrás de classes, aponte ele pro JSON também: @source "../kdf/**/*.json".
RUNTIME — JAVASCRIPT NO BACKEND
Instalou, tá pronto.
O Init cria o resto.
A própria instalação cria a pasta base kdf/ se ela não existir. Ele nunca sobrescreve o que já está lá.
import withKDF from "@kondeio/kdf/plugin"; export default withKDF({ dir: "./designs" })(nextConfig);