i18n är din översättning.
KDF är din design.
Båda bor i JSON.
Ett JSON-baserat lager för att styra design i server-side webbappar och agent-assisterade UI:n. Återkommande beslut — layout, spacing, typografi, styling — bor på ett enda ställe som dina agenter läser istället för att försöka återskapa allt över massa filer, sidor och gamla chattsessioner.
{ "$layout": ["hero", "footer"], "hero": { "wrapper": "mx-auto max-w-6xl px-6 py-20", "title": "@typography.h1", "cta-primary": "@button.cta" } }
En enda source of truth håller varje sida, komponent och agentsession konsekvent.
JSON definierar · kod renderar · data-kdf mappar tillbaka
Designen glider isär i
dina komponenter.
När klassnamn bara lever inuti .tsx-filer börjar varje sida sakta glida isär. Det funkar okej för en enda mänsklig kodare — men det är sjukt skört så fort agenter börjar pilla på UI:t.
<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
Samma knapp får plötsligt fem olika varianter. Spacing ändras från sida till sida. Varje ny agentsession måste lära sig reglerna från noll.
- — Agenter improviserar med färger, spacing, typografi och layout.
- — Användare tvingas rätta resultatet i chatten, varje gång.
- — Ändringar innebär att man måste leta igenom massa komponentfiler.
- — Upprepade sessioner tappar bort själva tanken bakom designen.
→ oändlig "större" · "mer blå" · "flytta vänster" iteration
Gör designen tydlig.
KDF gör samma sak för design som i18n gör för text: flyttar ut återkommande beslut från komponentfilerna och in i JSON. Det renderade UI:t använder fortfarande helt vanlig CSS — det som ändras är vem som äger den.
{ "hero": { "title": "text-5xl font-semibold tracking-tight" } }
const d = getDesign("homepage"); <h1 data-kdf="hero.title" className={d("hero.title")}>
Ett bibliotek säger vad.
KDF säger vilket.
Ett designbibliotek ger dig en Button. KDF berättar att just den här är homepage.hero.cta-primary, renderas som en Button, och stajlas med detta token. Det lägger till den exakta mappningen som bibliotek ofta skippar — från element till designbeslut.
Sex symboler.
En grammatik.
KDF lagrar klassnamn, delade referenser, sektionsordning och CSS-variabler. Det lagrar aldrig affärslogik, eventhandlers, datahämtning, behörigheter eller tillgänglighetsbeteenden.
Varje element som använder ett token bär med sig en matchande sökväg. DOM-noder kan spåras raka vägen tillbaka till JSON — perfekt för scanners, tester och granskning av agenter.
Löser upp en sökväg till dess className-sträng. d.css() returnerar objektet med CSS-variabler.
Peka på ett återanvändbart token i shared/. Refs kan kedjas ihop och utökas med extra klasser.
En array av sektionsnycklar. Listade sektioner renderas i rätt ordning; de som saknas döljs av värdappen.
Metadata för agenter och värdverktyg — vilken komponent som renderar detta token, plus hints om varianter och storlek.
Värden som inte går att uttrycka som återanvändbara klasser appliceras som inline style-variabler via d.css().
Delade standardvärden.
Overrides per sida.
Design-tokens bor på två ställen: återanvändbara standardvärden i shared/, och per-sida-komposition som bara skriver över exakt det som behövs. Två CSS-filer, som du som användare äger, täcker first paint och fallback-lösningar.
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
En referens som @button.cta hämtas från sidans shared/, sedan en överordnad shared/, och till sist sidans tokens. Mallar skriver bara över det de behöver och ärver resten.
Designen löses upp på servern; webbläsaren får färdiga klass-strängar. Kritisk CSS laddas vid first paint, resten kommer efter — ingen renderingstyngd dumpas på svaga klienter.
Importeras av appen så att designvariabler och no-FOUC-overrides kommer med direkt vid first paint — innan något hinner blinka till.
/* konde-server.css */ :root { --kdf-primary: #1F8F47; } [data-kdf="hero.slider"] { display: none; }
Laddas efter ramverket och appens CSS för justeringar, experiment och escape hatches — finlir som aldrig behöver blockera renderingen.
/* konde.css */ [data-kdf="hero.title"] { letter-spacing: -0.02em; } [data-kdf="hero.wrapper"] { gap: 3rem; }
→ KDF skapar båda filerna en gång och skriver aldrig över dem sen. Pluginet exponerar sökvägarna via miljövariabler - din app sköter importerna; inget injiceras i smyg åt dig.
Byt design
precis som du byter språk.
Samma sätt som i18n byter språk, byter KDF designmallar. Samma app, samma komponenter, samma kod — bara peka om KDF_DIR till en annan designmapp och hela utseendet byts ut.
designs/ lander/ shared/ homepage.json newlander/ shared/ homepage.json
// next.config.ts withKDF({ dir: "./designs/lander" })(nextConfig);
Lös upp på servern.
Skicka ner strängar.
KDF-kärnan läser JSON från disken, så den körs server-side: Next.js Server Components, Astro-renderingar, Hono-handlers. Lös upp klasserna där och skicka sedan ner rena strängar till klientkomponenterna.
import { getDesign, cn } from "@kondeio/kdf"; const d = getDesign("homepage"); <button data-kdf="hero.cta" className={cn(d("hero.cta"), isActive)}>Start</button>
→ upplöst className-sträng
→ objekt med CSS-variabler
Slå ihop villkorliga klasser, droppa falsy-värden, ta bort dubbletter — 100% fri från semantik som standard.
Produktion cachar; dev utvärderar på nytt baserat på mtime & storlek.
Det sitter ovanpå
din stack.
STYLING — LAGRAR KLASSNAMN, INTE CSS
KDF är ingen CSS-motor. Tokens rymmer vilka klass-strängar som helst som ditt stylingsystem fattar. Om ditt ramverk skannar källfiler, peka det mot JSON-filerna också: @source "../kdf/**/*.json".
RUNTIME — SERVER-SIDE JAVASCRIPT
Installera en gång.
Init bygger upp resten.
När du installerar sätts även en grundläggande kdf/-mapp upp om den inte redan finns. Filer som redan finns skrivs aldrig över.
import withKDF from "@kondeio/kdf/plugin"; export default withKDF({ dir: "./designs" })(nextConfig);