L'i18n, c'est pour vos trads.
KDF, c'est pour votre design.
Les deux vivent en JSON.
Une couche de coordination design basée sur JSON pour vos apps web côté serveur et vos UI assistées par des agents. Les décisions répétables — layout, espaces, typo, styles de composants — se trouvent dans une source de vérité unique que vos agents lisent, au lieu de fouiller partout dans les fichiers, les pages et les anciennes sessions.
{ "$layout": ["hero", "footer"], "hero": { "wrapper": "mx-auto max-w-6xl px-6 py-20", "title": "@typography.h1", "cta-primary": "@button.cta" } }
Une source de vérité unique garantit la cohérence de chaque page, composant et session d'agent.
Le JSON définit · le code fait le rendu · data-kdf fait le lien
Le design dérive dans
vos composants.
Quand les noms de classes vivent seulement dans les fichiers .tsx, chaque page diverge petit à petit. Ça passe quand c'est un seul dev humain qui édite le truc, mais ça devient super fragile dès que des agents commencent à toucher à l'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
Le même bouton gagne discrètement cinq variantes. Les espaces changent d'une page à l'autre. Chaque nouvelle session d'agent doit redécouvrir les règles depuis zéro.
- — Les agents improvisent avec les couleurs, les espaces, la typo et le layout.
- — Les utilisateurs corrigent le résultat via le chat, à chaque fois.
- — Faire des modifs implique de chercher un peu partout dans les fichiers de composants.
- — Les sessions à répétition perdent l'intention du design original.
→ des itérations "plus grand" · "plus bleu" · "décale à gauche" sans fin
Rendez le design explicite.
KDF fait pour le design ce que l'i18n fait pour le texte : il sort les décisions répétables des fichiers de composants pour les mettre dans du JSON. L'UI générée utilise toujours du CSS standard — ce qui change, c'est à qui appartient la responsabilité.
{ "hero": { "title": "text-5xl font-semibold tracking-tight" } }
const d = getDesign("homepage"); <h1 data-kdf="hero.title" className={d("hero.title")}>
Une librairie te dit ce que c'est.
KDF te dit lequel.
Une librairie de design te donne un Button. KDF te dit que c'est homepage.hero.cta-primary, rendu en tant que Button, et stylé avec ce token. Ça ajoute le mapping qui manque aux librairies : relier un élément à une décision de design.
Six symboles.
Une seule grammaire.
KDF stocke les noms de classes, les références partagées, l'ordre des sections et les custom properties CSS. Ça ne stocke jamais la logique métier, les handlers d'événements, le fetch de data, les permissions ou l'accessibilité.
Chaque élément utilisant un token transporte le chemin correspondant. Les nœuds du DOM remontent direct au JSON — top pour les scanners, les tests et la review par des agents.
Résout un chemin pour récupérer son string de className. d.css() retourne l'objet de custom properties CSS.
Pointe vers un token réutilisable dans shared/. Les refs peuvent s'enchaîner et s'étendre avec des classes en plus.
Un tableau de clés de sections. Les sections listées s'affichent dans l'ordre ; celles qui manquent sont cachées par l'app hôte.
Des métadonnées pour les agents et les outils hôtes — quel composant rend ce token, plus des indices de variantes et de tailles.
Les valeurs qu'on ne peut pas exprimer comme des classes réutilisables, appliquées comme variables de style inline via d.css().
Valeurs par défaut partagées.
Overrides par page.
Les tokens de design vivent à deux endroits : des valeurs réutilisables par défaut dans shared/, et une compo par page qui écrase juste ce dont elle a besoin. Deux fichiers CSS que vous contrôlez couvrent le first paint et les escape hatches.
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
Une référence comme @button.cta se résout depuis le shared/ de la page, puis un shared/ parent, puis les tokens de la page. Les templates surchargent uniquement ce dont ils ont besoin et héritent du reste.
Le design se résout côté serveur ; le navigateur reçoit les strings de classes toutes prêtes. Le CSS critique arrive avec le premier paint, le reste charge ensuite — aucun coût de rendu balancé sur des clients lents.
Importé par l'app pour que les variables de design et les overrides anti-FOUC arrivent dès le tout premier paint — avant que quoi que ce soit ne clignote.
/* konde-server.css */ :root { --kdf-primary: #1F8F47; } [data-kdf="hero.slider"] { display: none; }
Chargé après le CSS du framework et de l'app pour les petits ajustements, les tests et les escape hatches — des réglages fins qui n'ont jamais besoin de bloquer le rendu.
/* konde.css */ [data-kdf="hero.title"] { letter-spacing: -0.02em; } [data-kdf="hero.wrapper"] { gap: 3rem; }
→ KDF crée les deux une seule fois et ne les écrase jamais. Le plugin expose leurs chemins via env - votre app s'occupe de gérer les imports ; rien n'est injecté dans votre dos.
Changez de design
comme on change de langue.
De la même façon que l'i18n change de langue, KDF change de template de design. Même app, mêmes composants, même code — pointez KDF_DIR vers un autre dossier de design et tout le look change direct.
designs/ lander/ shared/ homepage.json newlander/ shared/ homepage.json
// next.config.ts withKDF({ dir: "./designs/lander" })(nextConfig);
Résoudre sur le serveur.
Passer des strings en bas.
Le cœur de KDF lit le JSON depuis le disque, donc il tourne côté serveur : Server Components de Next.js, rendus Astro, handlers Hono. Résolvez les classes là-bas, puis passez de simples strings aux composants clients.
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 résolue
→ objet de custom-properties CSS
Concaténer des classes conditionnelles, virer les valeurs falsy, dédupliquer — sans sémantique par défaut.
En prod, ça met en cache ; en dev, ça revalide selon le mtime et la taille.
Ça se pose au-dessus de
votre stack.
STYLING — STOCKE DES NOMS DE CLASSES, PAS DU CSS
KDF n'est pas un moteur CSS. Les tokens gardent juste les strings de classes que votre système de style comprend. Si votre framework scanne les fichiers sources, pointez-le aussi sur les JSON : @source "../kdf/**/*.json".
RUNTIME — JAVASCRIPT CÔTÉ SERVEUR
Installez une fois.
Init génère le reste.
L'installation génère aussi un dossier kdf/ de base s'il n'y en a pas encore. Vos fichiers existants ne sont jamais écrasés.
import withKDF from "@kondeio/kdf/plugin"; export default withKDF({ dir: "./designs" })(nextConfig);