i18n es tu traducción.
KDF es tu diseño.
Ambos viven en JSON.
Una capa de coordinación de diseño basada en JSON para web apps server-side y UI asistida por agentes. Las decisiones repetibles —layout, espaciado, tipografía, estilos— viven en una sola fuente de la verdad que tus agentes leen en vez de andarlas adivinando por los archivos.
{ "$layout": ["hero", "footer"], "hero": { "wrapper": "mx-auto max-w-6xl px-6 py-20", "title": "@typography.h1", "cta-primary": "@button.cta" } }
Una única fuente de la verdad mantiene la coherencia en cada página, componente y sesión de agente.
El JSON define · el código renderiza · data-kdf mapea de vuelta
El diseño muta en
tus componentes.
Cuando los nombres de clase viven solo en los archivos .tsx, cada página empieza a desviarse lentamente. Esto funciona con un único humano editando, pero es súper frágil en cuanto los agentes empiezan a tocar la UI.
<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
El mismo botón de pronto tiene cinco variantes. El espaciado cambia página por página. Cada nueva sesión del agente tiene que volver a descubrir las reglas desde cero.
- — Los agentes se inventan colores, espaciados, tipografías y layouts.
- — Tienes que corregir el resultado por el chat, todo el rato.
- — Hacer cambios implica buscar entre archivos de componentes.
- — Las sesiones repetidas pierden la intención original del diseño.
→ un bucle infinito de iteraciones pidiendo '"más grande" · "más azul" · "a la izquierda"'
Haz explícito el diseño.
KDF hace por tu diseño lo que i18n hizo por tus textos: saca las decisiones repetitivas fuera de los componentes y las mete en un JSON. La UI se sigue renderizando con CSS normal — lo que cambia es quién es el dueño de esa decisión.
{ "hero": { "title": "text-5xl font-semibold tracking-tight" } }
const d = getDesign("homepage"); <h1 data-kdf="hero.title" className={d("hero.title")}>
Una librería te dice qué es.
KDF te dice cuál es..
Una librería de diseño te da un Botón. KDF te dice que esto es un homepage.hero.cta-primary, que se renderiza como Botón, estilado con este token. Añade el único enlace que se dejan las librerías: del elemento a la decisión de diseño.
Seis símbolos.
Una gramática.
KDF guarda nombres de clase, referencias compartidas, orden de secciones y custom properties de CSS. Jamás guarda lógica de negocio, event handlers, peticiones de datos, permisos o comportamiento de accesibilidad.
Cualquier elemento que use un token lleva consigo la ruta al mismo. Los nodos del DOM apuntan directo al JSON — para escáneres, tests y revisión de agentes.
Resuelve una ruta a su string de className. d.css() te devuelve el objeto con las custom properties CSS.
Apunta a un token reutilizable en shared/. Las referencias pueden encadenar y extenderse añadiendo clases extra.
Un array de claves de sección. Las secciones de la lista se renderizan en orden; la app se encarga de ocultar las que no estén.
Metadatos para agentes y tooling del host — indica qué componente pinta este token, además de pistas de tamaño y variantes.
Valores que no encajan como clases reutilizables. Se aplican como variables inline a través de d.css().
Defaults compartidos.
Overrides por página.
Los tokens viven en dos partes: los defaults reutilizables en shared/, y la composición por página que sobrescribe solo lo que toca. Dos archivos CSS tuyos cubren el primer pintado y las vías de escape.
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
Una referencia tipo @button.cta se busca primero en el shared/ de la página, luego en el shared/ padre y finalmente en los tokens. Las plantillas sobreescriben solo lo que necesitan y heredan el resto.
El diseño se resuelve en el servidor; al navegador le llegan solo strings de clase ya listos. El CSS crítico carga en el first paint y el resto después — cero carga de render inútil en dispositivos lentos.
Importado en la app para que las variables de diseño y overrides críticos lleguen en el mismo first paint — sin parpadeos (FOUC).
/* konde-server.css */ :root { --kdf-primary: #1F8F47; } [data-kdf="hero.slider"] { display: none; }
Carga después del framework y del CSS de tu app para ajustes, apaños rápidos y escape hatches — retoques que nunca deberían bloquear el renderizado inicial.
/* konde.css */ [data-kdf="hero.title"] { letter-spacing: -0.02em; } [data-kdf="hero.wrapper"] { gap: 3rem; }
→ KDF los genera solo la primera vez y nunca los sobrescribe. El plugin expone las rutas en variables de entorno: tu app hace los imports; no hay inyección mágica de código.
Cambia de diseño
como cambias de idioma.
Igual que i18n cambia de idioma, KDF te permite cambiar de plantilla. Misma app, mismos componentes, mismo código — con solo apuntar la variable KDF_DIR a otra carpeta, todo el look and feel se transforma.
designs/ lander/ shared/ homepage.json newlander/ shared/ homepage.json
// next.config.ts withKDF({ dir: "./designs/lander" })(nextConfig);
Resuelve en servidor.
Pasa strings al cliente.
El core de KDF lee JSON directamente del disco, así que va en servidor: Next.js Server Components, renders de Astro, handlers en Hono. Resuelve las clases ahí y mándale strings limpios a los componentes de cliente.
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 resuelto
→ objeto con las custom properties CSS
Junta clases condicionales, filtra valores falsy, desduplica — sin lógica semántica por defecto.
En producción tira de caché; en dev revalida por mtime y peso del archivo.
Se monta encima
de tu stack.
ESTILOS — GUARDA CLASES, NO CSS
KDF no es un motor CSS. Los tokens guardan los strings que tu sistema de clases espere. Si tu framework escanea tus ficheros fuente, añádele el JSON: @source "../kdf/**/*.json".
RUNTIME — JAVASCRIPT EN SERVIDOR
Se instala una vez.
El init te monta el resto.
Al instalar te crea una carpeta kdf/ base si no la tenías ya. Nunca sobrescribimos archivos existentes.
import withKDF from "@kondeio/kdf/plugin"; export default withKDF({ dir: "./designs" })(nextConfig);