i18n is voor je vertalingen.
KDF is voor je design.
Beide leven in JSON.
Een JSON-gebaseerde design-coördinatielaag voor server-side web apps en agent-gestuurde UI. Repeterende keuzes — layout, spacing, typografie en component-styling — leven in één enkele source of truth die je agents moeiteloos uitlezen in plaats van eindeloos te raden in verspreide files, pagina's en eerdere sessies.
{ "$layout": ["hero", "footer"], "hero": { "wrapper": "mx-auto max-w-6xl px-6 py-20", "title": "@typography.h1", "cta-primary": "@button.cta" } }
Eén strakke source of truth houdt elke pagina, component en agent-sessie netjes in sync.
JSON definieert · code rendert · data-kdf mapt het terug
Design sluipt ongemerkt
je componenten in.
Wanneer class names alleen in je .tsx-files staan, divergeert elke pagina langzaam. Voor één menselijke developer is dat nog wel te fixen — maar het breekt keihard zodra AI-agents aan je UI gaan knutselen.
<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
Dezelfde button krijgt stiekem vijf varianten. Spacing verspringt per pagina. Elke nieuwe agent-sessie moet de regels weer helemaal opnieuw uitvinden.
- — Agents improviseren er lustig op los met kleuren, spacing, typografie en layout.
- — Users moeten telkens via de chat de boel weer lopen rechttrekken.
- — Aanpassingen betekent eindeloos grep-en door je component-files.
- — Bij elke sessie verlies je iets van je design-intentie.
→ eindeloos "groter" · "meer blauw" · "naar links" itereren
Maak design expliciet.
KDF doet voor design exact wat i18n doet voor tekst: repeterende keuzes weghalen uit je componenten en centraal beheren in JSON. De gerenderde UI gebruikt onder water nog steeds pure CSS — het enige wat verandert is het ownership.
{ "hero": { "title": "text-5xl font-semibold tracking-tight" } }
const d = getDesign("homepage"); <h1 data-kdf="hero.title" className={d("hero.title")}>
Een library roept 'wat'.
KDF bepaalt 'welke'.
Een design library geeft je een Button. KDF vertelt je strak dat dit de homepage.hero.cta-primary is, toevallig gerenderd als een Button, met díé token-styling. Het slaat de broodnodige brug die libraries altijd missen: van element direct naar de design-keuze.
Zes symbolen.
Eén grammatica.
KDF snapt class names, shared references, sectie-volgorde en CSS custom properties. Het bemoeit zich nóóit met business logic, event handlers, data fetching, rechten of a11y-gedrag.
Elk element met een token tagt het pad mee in de DOM. Nodes wijzen zo direct terug naar de JSON — perfect voor scanners, test-suites en agent reviews.
Vertaalt een pad strak naar z'n className-string. d.css() spuugt het CSS custom properties object voor je uit.
Prik naar een herbruikbare token in shared/. Refs kun je naadloos chainen of overriden met extra classes.
Gewoon een array van sectie-keys. Wat in de array zit, wordt netjes op volgorde gerenderd; de rest klapt je app slim dicht.
Handige metadata voor agents en devtools — hint meteen welke component (en variant of size) deze token afhandelt.
Losse waarden die je niet als class kwijt wil, gewoon direct als inline style variables ingeschoten via d.css().
Shared defaults.
Page overrides.
Design tokens leven slim op twee plekken: solide defaults in shared/, en per pagina kleine overrides voor wat maatwerk. Twee losse CSS-files regelen perfect de first paint én je snelle ontsnappingsroutes.
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
Een call naar @button.cta checkt eerst de page shared/, dan root shared/ en dan de pure page tokens. Templates overriden dus puur wat lokaal afwijkt.
Design-resolutie gebeurt op de server; de browser hapt alleen statische class-strings weg. Critical CSS belandt veilig in de first paint, de bulk laadt pas daarna — dus nul onnodige lagere framerates.
Geïmporteerd in de root zodat core variables en anti-FOUC hacks direct in de first paint landen — nog vóórdat er überhaupt iets kan knipperen.
/* konde-server.css */ :root { --kdf-primary: #1F8F47; } [data-kdf="hero.slider"] { display: none; }
Laadt ontspannen na je framework CSS in; ideaal voor snelle tweaks, tests en escape hatches. Blokkeert je paint niet.
/* konde.css */ [data-kdf="hero.title"] { letter-spacing: -0.02em; } [data-kdf="hero.wrapper"] { gap: 3rem; }
→ KDF genereert beide files eenmalig en komt er dan nooit meer aan. De paden staan in je env, je importeert ze zelf — nul enge magie of build injecties.
Wissel van design
zoals je van taal wisselt.
Net zoals i18n tussen talen swapt, schiet KDF tussen complete design templates. Zelfde app, zelfde componenten, zelfde code — gooi gewoon KDF_DIR naar een andere directory en heel je look-and-feel draait om.
designs/ lander/ shared/ homepage.json newlander/ shared/ homepage.json
// next.config.ts withKDF({ dir: "./designs/lander" })(nextConfig);
Resolve op de server.
Geef strings door.
De KDF-core slikt JSON zo van disk en draait dus loeisnel server-side: in Next.js Server Components, Astro of Hono. Pak de classes daar en geef schone, platte strings door aan de client.
import { getDesign, cn } from "@kondeio/kdf"; const d = getDesign("homepage"); <button data-kdf="hero.cta" className={cn(d("hero.cta"), isActive)}>Start</button>
→ uitgepakte className string
→ kant-en-klaar CSS custom-properties object
Merge slim class-strings, strip falsy shit en drop dubbelingen — out-of-the-box.
Cacht stevig in prod; in dev ververst 'ie snel op mtime & filesize changes.
Het draait puur bovenop
jouw bestaande stack.
STYLING — SLAAT CLASS NAMES OP, GEEN CSS
KDF bemoeit zich niet met je CSS engine. De tokens bevatten simpelweg class-strings van wat jij gebruikt. Werkt jouw framework met file-scanners (zoals Tailwind)? Point 'm dan even naar de JSON: @source "../kdf/**/*.json".
RUNTIME — SERVER-SIDE JAVASCRIPT
Installeer eenmalig.
Init zet alles voor je klaar.
Bij de eerste run zet de setup meteen de hele kdf/ mappenstructuur op. Heb je al wat staan? Dan blijft 'ie daar mooi van af.
import withKDF from "@kondeio/kdf/plugin"; export default withKDF({ dir: "./designs" })(nextConfig);